Mongoose: Populate path using field other than _id
Asked Answered
G

2

9

By default mongoose/mongo will populate a path using the _id field, and by it seems like there is no way to change the _id to something else.

Here are my two models which are connected with one-to-many relationship:

const playlistSchema = new mongoose.Schema({
  externalId: String,
  title: String,
  videos: [{
    type: mongoose.Schema.Types.ObjectId,
    ref: 'Video',
  }],
});

const videoSchema = new mongoose.Schema({
  externalId: String,
  title: String,
});

Normally, when querying a playlist you would populate videos just with .populate('videos'), but in my case I would like to use the externalId field instead of the default _id. Is that possible?

Greenhorn answered 7/4, 2020 at 20:42 Comment(1)
this might help, github.com/Automattic/mongoose/issues/…, but if doesn't use $lookup aggregationHelles
E
8

As far as I know, the way to achieve this with mongoose presently is by using virtuals. When populating virtuals, you can specify the localField and foreignField to whatever you want, so you are no longer bound to the default _id as foreignField. More details about this here.

For the scenario described in your question, you would need to add a virtual to the playerlistSchema, something like this:

playlistSchema.virtual('videoList', {
  ref: 'Video', // The model to use
  localField: 'videos', // The field in playerListSchema
  foreignField: 'externalId', // The field on videoSchema. This can be whatever you want.
});

Now, whenever you query for player lists, you can populate the videoList virtual to get the referenced video documents.

PlaylistModel
  .findOne({
    // ... whatever your find query needs to be
  })
  .populate('videoList')
  .exec(function (error, playList) {
    /* if a playList document is returned */
    playList.videoList; // The would be the populated array of videos
  })
Eared answered 8/4, 2020 at 10:43 Comment(1)
I think it's virtual not virtualsApoplectic
J
0

2024 - Mongoose version 8

There is a better and simpler way to achieve this:

  PlaylistModel.find()
    .populate({
      path: 'videos',
      model: 'Video',
      select: 'title',
      foreignField: 'externalId',
    })
  • path: specifies the field in the Announcement schema that you want to populate.
  • model: specifies the model to use for population.
  • select: specifies the fields to select from the referenced document.
  • foreignField: specifies the field in the referenced model (Video in this case) that is used to match with the local field (videos in playlistSchema) for populating references. (instead of the default _id)
Journeywork answered 7/1, 2024 at 18:9 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.