change need
change need

Reputation: 157

populate with condition in mongoose

I have a movie booking data like below

movie order schema

 {
    "movie_id": "5d64fb7975214a183bf10f5b",
    "variant_id": "5d64fda8fc7f911a77afd55c",

 }

and movie schema data like below

{  
   "_id":"5d64fb7975214a183bf10f5b",
   "description":"Sahoo movie ",
   "options":[  

   ],
   "variants":[  
      {  
         "enabled":true,
         "_id":"5d64fda8fc7f911a77afd55c",
         "variant_name":"",
         "regular_price":345,
         "sale_price":125,
         "stock_quantity":45,
      },
      {  
         "enabled":true,
         "_id":"5d661c8181a4572a27f048dd",
         "variant_name":"",
         "regular_price":120,
         "sale_price":50,
         "stock_quantity":10,
      }
   ],

   "on_sale":false,
   "variable":true
}

now I'm trying to querying the movie order

let data = await MovieOrder.find().populate(movie_id)

but it is giving movie details with all the variant.but what I'm looking for here is

In the movie order what is the variant_id is present based on that I need to populate the movie with variant based on that variant id on the movie order

Note: the result should be, what are the variant_id in the movie order schema is equal to variant id in the movie schema

Hope you guys understand my problem, please give me the solution

Upvotes: 1

Views: 182

Answers (1)

chridam
chridam

Reputation: 103375

With the way your schema is designed it is hard for populate to filter the movies variants array with the variant_id in the movies order as this is not how populate works.

In order to use populate properly, you would have to change the movies schema making the variants array as ref to Variants model. For example, your schema definitions would need to look like

Schema definitions

const mongoose = require('mongoose')
const Schema = mongoose.Schema

const variantSchema = new Schema({
    enabled: Boolean,
    variant_name: String,
    regular_price: Number,
    sale_price: Number,
    stock_quantity: Number
})

const Variant = mongoose.model('Variant', variantSchema)

const movieSchema = new Schema({
    description:  String,
    options:   [String],
    variants: [{ type: 'ObjectId', ref: 'Variant' }],
    on_sale: Boolean,
    variable: Boolean
})

const Movie = mongoose.model('Movie', movieSchema)


await MovieOrder.find().populate('movie_id variant_id')

This way your query just returns the movie and the variant it needs.


However, if the current schema design remains as it is, you can use $lookup in an aggregate pipeline to do the populate and then filter the resulting array using $filter on the variant that matches the variant_id field in your MovieOrder model:

await MovieOrder.aggregate([
    { '$lookup': {
        'from': 'movies',
        'localField': "movie_id",    // field in the movieorders collection
        'foreignField': "_id",  // field in the movies collection
        'as': "movie"
    } },
    { '$addFields': { 
        'movie': { '$arrayElemeAt': ['$movie', 0 ] }
    } },
    { '$addFields': { 
        'movie.variants': { 
            '$filter': {
                'input': '$movie.variants',
                'cond': { '$eq': ['$variant_id', '$$this._id'] }
            }
        }
    } },
]).exec()

Upvotes: 1

Related Questions