0

I am trying to solve an issue with the format of documents in a MongoDB depicted below.

{
  "_id": {
    "$oid": "68dc4f78e11553b3647231e2"
  },
  "name": "Dutch Bros",
  "address": "25 Down Street, Salt Lake City, UT",
  "facilities": [
    "Hot drinks",
    "Food"
  ],
  "coords": [
    -0.9690884,
    51.455041
  ],
  "reviews": [
    {
      "author": "John Smith",
      "rating": {
        "$numberDecimal": "5"
      },
      "createdOn": {
        "$date": "2025-09-30T06:00:00.000Z"
      },
      "reviewText": "Great Place. Would come back again!"
    },
    {
      "author": "Jane Doe",
      "rating": {
        "$numberDecimal": "4"
      },
      "createdOn": {
        "$date": "2025-09-30T06:00:00.000Z"
      },
      "reviewText": "Okay Place. Would come back again!"
    }
  ]
}

My goal is to match and return only review sub-document(s) based on an attribute it has such as ratings being equal to five. I know that I could take the reviews array as a whole and iterate over them to search the attributes for what I need, but I want to be able to find it directly in the MongoDB query so the MongoDB server does the work while it saves my express server any additional workload.

I guess what I am asking is how do I reference the iterable objects in the reviews array. I hope that was clear enough and I apologize if it wasn't!

I've successfully implemented a version that iterates in a for loop on the express server in the controller, but this is what I want to avoid. I've also tried using a .get() method on the returned array because I saw that it was an available method for the object, but that yielded an error. I've also tried to build a query which was close to what I believe the solution is going to be but I can't understand how MongoDB element matches an array item, see below for my failed attempt.

const monReview = await Loc
            .findById(req.params.locationid)
            .select('name reviews')
            .where('reviews')
            .elemMatch({$eq: req.params.reviewRating})
            .exec();  

1 Answer 1

0

Took me a moment but I figured out that I needed to use an aggregate instead.

var monReview = await Loc
            .aggregate([
                {$match: {_id: new mongoose.Types.ObjectId(req.params.locationid)}},
                {
                    $project: {
                        name: 1,
                        reviews: {
                            $filter: {
                                input: "$reviews",
                                as: "review",
                                cond: {$eq: ["$$review.rating", req.params.reviewRating]}
                            }
                        }
                    }
                }
            ]);

This now matches documents on the locationid and creates a projection for name and reviews as I had wanted. What actually achieves the goal is in the projection I filter the reviews based on the condition of being equal to the parameter passed for rating.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.