Search code examples
mongodbmongoosemongoose-populate

Mongoose search keyword for model and also the populate model


I have 2 models as:

Books.Schema = {
  id,
  name,
  description,
  type: ObjectID(populate to Types.Schema),
}

And Types.Schema as:

Types.Schema = {
  id,
  name,
}

I want to write a function to get all books that match the "searchKeyWords". I write a function like this:

let list = await Books.find({
   $or:[
      {"name": {"$regex": req.query.search}},
      {"description": {"$regex": req.query.search}}
       ]
})
list = await Types.populate(list, {path: "type", model: "Types", select: "id name", options: {lean: true}});

So when I type a searchKeyWord, it's only return books that includes the book.name and book.description. I want it also return the book.type.name

For example, when I type 'a', I want the function returns book.name.include(a) + book.description.include(a) and book.type.name.include(a)

I understand that because I get the query first into the list then populate with Types Schema, but is there any way to populate first and then filter the data in db query level (not nodejs)

Thank you very much!

EDIT!

I follow the answer of ISAE and it worked. I want to ask that how can I variabled the query condition. I tried:

var query = `$or: [
      {"name": {"$regex": req.query.search}},
      {"description": {"$regex": req.query.search}},
      {"tenant": {"$regex": tenantIds}}
]`
Books.find({query}).lean();

But it doesn't work. Thank you!


Solution

  • mongoose .populate() is executed on the query results, so you can't do that in one query. You'll need to run two queries, one to return a list of types, than another one to get the books.
    You may try something like this:

    let typeIds = await Types.find({
       name: {$regex: req.query.search}})
       .select("_id")
       .lean();
    
    let list = await Books.find({
       $or:[
          {name: {$regex: req.query.search}},
          {description: {$regex: req.query.search}},
          {type: {$in:typeIds}}
           ]
    }).populate("type").lean();
    

    BTW, I believe type is a reserved keyword in mongoose, you shouldn't use it in your schema. Use something like bookType instead.