4

I would like to query through the populated field. In this case, the populated field is reviews. So if my searched query matches the reviews tables description field... then return that book. Reviews is an array of objects and description is one of the keys in it.

I have tried using reviews[0].description in the query object but it didn't work.

getBookInfo: (req, res) => {
        const search = req.params.search;
        const query = { $or: [{ title: { $regex: search, $options: 'i' } }] };
        Books.find(query).populate('reviews').exec(function(err, books) {
            if (err) {
                return err;
            }
            return books;
        });
    }
Neil Lunn
  • 148,042
  • 36
  • 346
  • 317
HeelMega
  • 458
  • 8
  • 23
  • So You're searching in reviews not in books. Am I correct? – num8er Apr 20 '18 at 23:02
  • @num8er yes i want to search in both. So books field would be title and then also search the description from reviews – HeelMega Apr 20 '18 at 23:06
  • so you have a book schema with `title` and `description` as attributes right ? – Muhammad Usman Apr 20 '18 at 23:12
  • @GeorgeBailey yes that is correct. In the books schema... i have title, description, and reviews(its a reference to the reviews table). In the reviews table, i have title and description as well – HeelMega Apr 20 '18 at 23:14
  • `find( { $or: [ { title: { $regex: search, $options: 'i' } } ,{reviews: {$elemMatch: {description:{ $regex: search, $options: 'i' }}}}] } )` ?? – Muhammad Usman Apr 20 '18 at 23:17
  • @GeorgeBailey You're correct if reviews are kept in books collection document. But in example is used populate that means books collection keep review id-s in reviews. So You cannot query objectid-s for description field. – num8er Apr 20 '18 at 23:22
  • yeah. Didn't know that. Sorry for misunderstanding the question – Muhammad Usman Apr 20 '18 at 23:27
  • @GeorgeBailey in my experience it's better to build some index of reviews with book's necessary fields in it. It can be some collection/model `ReviewsIndex` or it can be ElasticSearch index to not make high load on mongodb – num8er Apr 20 '18 at 23:30
  • 1
    Yes that's what mostly used and appreciated. I totally agree – Muhammad Usman Apr 20 '18 at 23:31
  • @HeelMega I think You should create `BookSearchIndex` model and every-time when user write review additionally insert to that collection document that keep the `book` and `value` fields, where book is reference, and value is concatenation of `book.title + book.description + review.title + review.description` and when You do search for book, just do query to that index collection and retrieve Your book. Or just move something that helps easily do relational queries. – num8er Apr 20 '18 at 23:36
  • The question nominated to be duplicate. But it's incorrect. I don't know how it can be nominated to be duplicate of question that works with small data (`tags`) vs unlimited amount of data (`reviews`) ? – num8er Apr 21 '18 at 00:05

1 Answers1

1

You want to search for books and populate reviews that does match for Your query.

So by documentation You've right to use match for population.

Here You go:

getBookInfo: async (req, res) => {
  try {
    const search = req.params.search;

    // query for books matching by condition
    const query = { 
      $or: [
        { title: { $regex: search, $options: 'i' } },
        { description: { $regex: search, $options: 'i' } },
      ] 
    };

    // include reviews matching by conditions
    const include = {
      path: 'reviews',
      match: {
        description: { 
          $regex: search, 
          $options: 'i' 
        }
      },
      options: {limit: 5}
    };

    const books = await Books
                          .find(query)
                          .populate(include)
                          .lean();
    res.status(200).send(books);
  }
  catch (error) {
    res.status(500).send(error);
  }
};

UPDATE:

As I understand You want to query both review and book.

  1. have book field in Review model that will keep book _id, title and description.
  2. when user add's a review just put that book data into review document.
  3. query directly reviews collection.
num8er
  • 18,604
  • 3
  • 43
  • 57