0

I'm looking to query the item data from my mongoose data collection. I only need the "stocked" boolean value for the user "456" item "4", but when I query in my example, I instead receive the entire user object.

Data:

data = [{
    userId: "123",
    items: [{
        item: "2",
        stocked: false
      },
      {
        item: "3",
        stocked: true
      },
      {
        ...more items
      }
    ],
  },

  {
    userId: "456",
    items: [{
        item: "1",
        stocked: true
      },
      {
        item: "4",
        stocked: true
      },
      {
        ...more items
      }
    ],
  },

  {
    ...more users
  }
]

Route:

router.post("/example", (req, res) => {

  Data.findOne({
      userId: "456",
      "items.item": "4"
    }
  }).then((item) => {
  console.log(item) // desired: {item: "4", stocked: true}

  if (item.stocked) {
    console.log("Item is stocked!")
  }
})

})

Problem: The response is the entire user object including all items:

{
  userId: "456",
  items: [{
      item: "1",
      stocked: true
    },
    {
      item: "4",
      stocked: true
    },
    {
      ...more items
    }
  ],
},

Desired response: { item: "4", stocked: true }

Any tips or help would be appreciated!

1
  • I understand I can use dot notation to access the stocked value within, but I'm looking to do it completely with the mongoose query. Thanks. Commented Jan 5, 2021 at 22:45

1 Answer 1

0

Using the aggregation pipeline you can make use of $elemMatch or $unwind.

The $elemMatch operator limits the contents of an field from the query results to contain only the first element matching the $elemMatch condition.

Data.aggregate([
 {$match: {userId: "456", "items.item": "4"}},
 {$project: { items: { $elemMatch: { "items.item": "4"} }}}
]);

OR

The $unwind will return all element that meet your criteria.

Data.aggregate([
 {$match: {userId: "456", "items.item": "4"}},
 {$unwind: "$items"},
 {$match: { "items.item": "4"} }
])
Sign up to request clarification or add additional context in comments.

3 Comments

Hey, thank you @Haniel Baez so much! The first option didn't work so I researched it and found that you may not be able to use $elemMatch in aggregate functions: stackoverflow.com/a/36651117/14849955 .That aside, the second one did work for my needs. The interesting part is that it still keeps the userId: "456" in the object when it is returned. Here's my response: { userId: "456", item: "4", stocked: true }, works great, but I'm still looking to only get the response { item: "4", stocked: true }.
Interestingly enough, Data.aggregate([ {$match: {userId: "456", "items.item": "4"}}]) works just as well as the second approach
You can add a $projection state, to eliminate the userId from the result; something like this --> { $project: { userId: 0, item: 1, stocked: 1 } }

Your Answer

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