2

Restaurants is a collection and has objects like below:

{
    _id: new ObjectId("61723c7378b6d3a5a02d908e"),
    name: 'The Blue Hotel',
    location: 'Noon city, New York',
    phoneNumber: '122-536-7890',
    website: 'http://www.bluehotel.com',
    priceRange: '$$$',
    cuisines: [ 'Mexican', 'Italian' ],
    overallRating: 0,
    serviceOptions: { dineIn: true, takeOut: true, delivery: true },
    reviews: [
      {
        _id: new ObjectId("61736a0f65b9931b9e428789"),
        title: 'asd',
        reviewer: 'khoh',
        rating: 3,
        dateOfReview: '5/12/2002',
        review: 'hey'
      },
        _id: new ObjectId("61736a0f65b9931b9e428790"),
        title: 'dom',
        reviewer: 'firuu',
        rating: 4,
        dateOfReview: '25/1/2002',
        review: ' bruh'
      }
    ]
  }

I am using the below code to find this object based on the review id provided

async get(reviewId) {

    const restaurantsCollection = await restaurants();
    reviewId = ObjectId(reviewId)
    const r = await restaurantsCollection.findOne({reviews: {$elemMatch: {_id: reviewId}}})
    return r

This returns the whole object from the restaurant collection, what do I do if I want only the review displayed whose id is provided in get(reviewID)

Output:

{
  _id: new ObjectId("61736a0f65b9931b9e428790"),
   title: 'dom',
   reviewer: 'firuu',
   rating: 4,
   dateOfReview: '25/1/2002',
   review: ' bruh'
}

3 Answers 3

3

With a projection, specify the fields to return

The following returns only the review whose id is provided in get(reviewID)

async get(reviewId) {
  const restaurantsCollection = await restaurants();
  reviewId = ObjectId(reviewId)

  const r = await restaurantsCollection.findOne(
    { reviews: { $elemMatch: { _id: reviewId } } },
    { "reviews.$": 1 }
  )

  return r
}

Test Here

You can also use find instead of fineOne

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

5 Comments

It returns all the reviews, I want to display only the matched review
Hi, I have updated the code. Please check @swombhai
I still get the entire object when I return r, not sure why
the findOne method of node js as far as i know takes the projection as option,so it should replaced by {"projection" : { "reviews.$": true }} test it maybe
Is there a way to represent the _id with a string instead of new ObjectID? Can toString() be added to findOne function?
1

Query

  • replace the ObjectId("61736a0f65b9931b9e428789") with reviewId
  • this will return the reviews that match the _id in an array
  • if you want to get the first only, in case there is always max 1 you can replace the last project with {"$project": {"_id": 0, "review": {"$arrayElemAt": ["$reviews", 0]}}}

*not sure if this is what you need

Test code here

aggregate(
[{"$match": {"reviews._id": ObjectId("61736a0f65b9931b9e428789")}}
 {"$set": 
   {"reviews": 
     {"$filter": 
       {"input": "$reviews",
        "cond": 
        {"$eq": ["$$this._id", ObjectId("61736a0f65b9931b9e428789")]}}}}},
  {"$project": {"_id": 0, "reviews": 1}}])

3 Comments

Do I have to put toArray() anywhere? I replaced the code but didn't get the output
yes aggreagte will return a cursor , use result.toArray()
the @Pramisha answer looks more like your code, i think use the other answer, this is aggregate solution, here you can do it with find only.
0

This might not be the correct answer of your question but you can try something like this.

const r = await restaurantsCollection.findOne({reviews: {$elemMatch: {_id: reviewId}}})?.reviews.find(review => review._id.equals(reviewId))

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.