Skip to content
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

Populate silently fails for cached documents unless lean() is set #17

Closed
0x62 opened this issue Jan 23, 2017 · 5 comments
Closed

Populate silently fails for cached documents unless lean() is set #17

0x62 opened this issue Jan 23, 2017 · 5 comments

Comments

@0x62
Copy link
Contributor

0x62 commented Jan 23, 2017

If using .populate(), you must set .lean(), or fields will not be populated.

Without .lean():

Model
  .findOne(id)
  .populate('field')
  .cache(30)
  .exec((err, item) => {
    // item.field is just ObjectId
  })

With .lean():

Model
  .findOne(id)
  .populate('field')
  .lean()
  .cache(30)
  .exec((err, item) => {
    // item.field is { key: value }
  })

Is there any reason why there is no support for caching populated fields without lean?

@0x62
Copy link
Contributor Author

0x62 commented Jan 23, 2017

I've tracked this back to inflateModel, which is used to Mongoosify a document (but only when lean() is not set). Seems to be related to Automattic/mongoose#4727, perhaps some documentation should be added for this?

Also, it appears to use Model.inflate, which I believe has been replaced with Model.hydrate.

@0x62 0x62 changed the title Cache incorrect when using populate unless lean is set Populate silently fails for cached documents unless lean() is set Jan 23, 2017
@boblauer
Copy link
Owner

hhmm, this could be tricky.

I'm thinking I can probably check the query and determine which fields should be populated, and then do that manually. But this gets pretty tricky when we start doing things like .populate('user', 'name email age').

I'll have to play around with it a bit.

@0x62
Copy link
Contributor Author

0x62 commented Jan 26, 2017

I started looking into it, and sortof came up with a workaround (but its very hacky). I added a virtual to each collection, __modelName. When populating, it recursively iterates each layer of the document till it finds the deepest nested object with the keys _id and __modelName. It then splits these into separate objects, and hydrates them separately (using mongoose.model(__modelName).hydrate). Finally, it hydrates the root document, then replaces each of the populated fields with their hydrated objects.

I'll tidy up the code a bit, and post it. Unfortunately, I wasn't able to support populated arrays without reimplementing mongooses dot-notation resolver.

The approach of hydrating each child document isn't ideal, and is only required if you want to retain the ability to use the child's methods/virtuals. Potentially, a better middle ground could be monkeypatching hydrate to mongoosify the root document, but completely ignore child documents (rather than processing { _id: 'xyz' } into ObjectId(xyz) which discards the other data).

@simllll
Copy link

simllll commented Feb 7, 2017

@0x62 are you still posting your code some time? :) thanks

@boblauer
Copy link
Owner

Closing this due to inactivity. If anyone needs this functionality, for the time being I would recommend running your query as .lean and then hydrating the data yourself manually using this approach: Automattic/mongoose#4727 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants