New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: fields and population selection with Local API / REST #5942
base: beta
Are you sure you want to change the base?
Conversation
…t/select-fields
Hi again! // Populates only `item` field doc - all fields.
const doc = await payload.findByID({
collection: docWithRelationSlug,
id: docWithRelationId,
depth: 1,
populate: {
item: true,
},
});
// Populates only `item` feield doc and selects only title field from population
const doc = await payload.findByID({
collection: docWithRelationSlug,
id: docWithRelationId,
depth: 1,
populate: {
item: {
select: {
title: true,
},
},
},
});
// Populates `item` field doc and `nested` field doc inside, all fields
const doc = await payload.findByID({
collection: docWithRelationSlug,
id: docWithRelationId,
depth: 2,
populate: {
item: {
populate: {
nested: true,
},
},
},
});
// Populates `item` inside nested to array field
const doc = await payload.findByID({
collection: docWithRelationSlug,
id: docWithRelationId,
depth: 1,
populate: {
'array.item': true,
},
})
// Polymorphic population of the field named `polymorphic`
const doc = await payload.findByID({
collection: docWithRelationSlug,
id: docWithRelationId,
populate: {
polymorphic: [
{
relationTo: "relationships-items-nested",
value: {
select: {
title: true,
},
},
},
],
},
}); Configuration for Relationships / Upload fields: // By default if in query `populate` is not provided, will be used this configuration for that field
{
name: 'withDefaultPopulate',
type: 'relationship',
relationTo: 'relationships-items',
defaultPopulate: {
select: {
title: true,
},
},
},
// The same for polymorphic
{
name: 'polymorphicDefault',
type: 'relationship',
defaultPopulate: [
{
relationTo: 'relationships-items',
value: {
select: {
title: true,
},
},
},
],
relationTo: ['relationships-items', 'relationships-items-nested'],
}, It still actually respects |
Happy to share that it passes all my 33 integration tests with both, mongodb and postgres adapters. |
Hey @r1tsuu super interesting PR, thank you for your contribution! One thing I'm worried about are hooks. What if you added a field or collection hook to a field which depends on the value on another field? That hook would break if the other field isn't queried. |
Yes i thought about this too and i think that's basically the cost of optimizations. You need to ensure that the non selected data isn't used in the hooks. Also it's only a problem here with |
@AlessioGr Hi, any chance it could be reviewed? Or is it something that you don't want bring to now? While there's no a discussion with roadmap to this, i believe i saw somewhere that field selection feature is planned. |
Hey @r1tsuu just a quick update from our side, this definitely needs to make its way into Payload but our team won't likely have bandwidth to give this PR the justice that it needs until at least a week from now or so. But we'll get there. My big question will be TypeScript. I have not looked at the code yet here, but have you solved typing accordingly as well? I will report back here shortly! |
Hi, thank you for the message here! export type Select = {
[key: string]: Select | boolean
}
export type PopulatePolymorphicValue = {
relationTo: string
value:
| {
populate?: Populate
select?: Select
}
| boolean
}[]
export type PopulateSingleValue = {
populate?: Populate
select?: Select
}
export type PopulateValue = PopulatePolymorphicValue | PopulateSingleValue
export type Populate = {
[key: string]: PopulateValue | boolean
} It's far from full-typed system for this feature of course, but it matches our current implementation of type for Do you mean it should work like in for example Prisma or Drizzle? It maybe would be better if we had some additional type-gen for these params, like i believe we plan with Also i have few considerations:
// This will work
const doc = await payload.findByID({
collection: docWithRelationSlug,
id: docWithRelationId,
depth: 1,
populate: {
item: true,
},
});
// This will work. And only `item` will be populed on the depth level 1
const doc = await payload.findByID({
collection: docWithRelationSlug,
id: docWithRelationId,
depth: 1,
populate: {
item: true,
},
// This - won't, as we haven't increased `depth` to 2.
const doc = await payload.findByID({
collection: docWithRelationSlug,
id: docWithRelationId,
depth: 1,
populate: {
item: {
populate: {
nested: true,
},
},
},
});
}); This was done in order to ensure that we can't exceed |
Description
The problem: you want to create a link field, which has relation to Pages collection. But your Pages collection contains many many fields and as well relations, fetching all of that just for
slug
seems too much unnecessary.This PR perfectly solves this i believe.
Added 2 parameters to operations / endpoints (
select
,populate
) and 1 parameter to a relationship field config (defaultPopulate
), more examples in the separated test config:select
- allows to specify which fields to return from a database.Considerations: the document's id, array / blocks items that are selected id's,
blockName
,blockType
, relationship ids within selected field depth - are automatically selected.populate
- allows you to specify which relationship fields to populate, as well you can specifyselect
for the current population and nestedpopulate
. It still respectsdepth
parameter just to not break the current logic, but we can tweak that i think, it won't populate other relations in the samedepth
, but if yourdepth
value is not enough it won't populate specified fields.Example:
defaultPopulate
- configuration for relationships / upload fields:Type of change
Checklist: