Search code examples
mongodbaggregationdocument-database

Query to get specific sub-doc using aggregation in mongoDB?


I'd like to know a query in which I could get a specific sub-doc using it's ObjectId- or even it's "store" name if it's easier- using the aggregation method. I'm pretty sure I can use $project but I'm not sure how to apply that to an ObjectId.

I can use the find method but I need it to be in an aggregation method so mongo will return to me the item's names and not it's ObjectId.

db.stores.aggregate([
  {$unwind: '$inventory'},
  {$lookup: {
    from: 'items',
    localField: 'inventory.item',
    foreignField: '_id',
    as: 'itemsData'
   }},
  {$unwind: '$itemsData'},
  {$group:{
    _id: "$_id",
    inventory: { $push: "$inventory" },
    itemsData: { $push: "$itemsData" }
  }}
]).pretty()

I have five stores in my store collection. This query returns all five documents like the code below this, just five times. But I want to specify stores to be returned using it's ObjectId.


{
        "_id" : ObjectId("5cc0d6ad1ea502abb28b52cc"),
        "inventory" : [
                {
                        "item" : ObjectId("5cbe70bd1ea502abb28b52a4"),
                        "amount" : 9
                },
                {
                        "item" : ObjectId("5cbe70bd1ea502abb28b52a1"),
                        "amount" : 5
                },
                {
                        "item" : ObjectId("5cbe70bd1ea502abb28b52a7"),
                        "amount" : 2
                },
                {
                        "item" : ObjectId("5cbe70bd1ea502abb28b529e"),
                        "amount" : 5
                }
        ],
        "itemsData" : [
                {
                        "_id" : ObjectId("5cbe70bd1ea502abb28b52a4"),
                        "item" : "beans",
                        "price" : NumberDecimal("53,75")
                },
                {
                        "_id" : ObjectId("5cbe70bd1ea502abb28b52a1"),
                        "item" : "bananas",
                        "price" : NumberDecimal("5.00")
                },
                {
                        "_id" : ObjectId("5cbe70bd1ea502abb28b52a7"),
                        "item" : "watermelon",
                        "price" : NumberDecimal("3.50")
                },
                {
                        "_id" : ObjectId("5cbe70bd1ea502abb28b529e"),
                        "item" : "broccoli",
                        "price" : NumberDecimal("5.50")
                }
        ]

}

I want the query to return back the code just like the one above, with only one store and not five. I'm not sure how to use $project if it's suitable for this task.


Solution

  • As you said only one store data to be return, so you can use $limit :

    db.stores.aggregate([
       {$unwind: '$inventory'},
       {$lookup: {
          from: 'items',
          localField: 'inventory.item',
          foreignField: '_id',
          as: 'itemsData'
       }},
       {$unwind: '$itemsData'},
       {$group:{
          _id: "$_id",
          inventory: { $push: "$inventory" },
          itemsData: { $push: "$itemsData" }
       }},
       { $limit : 1}
      ]).pretty()
    

    now, if you want to return specific store data to be return use $match Query :

    db.stores.aggregate([
       { $match : { "_id" : ObjectId("5cc0d6ad1ea502abb28b52cc") }},
       {$unwind: '$inventory'},
       {$lookup: {
          from: 'items',
          localField: 'inventory.item',
          foreignField: '_id',
          as: 'itemsData'
       }},
       {$unwind: '$itemsData'},
       {$group:{
          _id: "$_id",
          inventory: { $push: "$inventory" },
          itemsData: { $push: "$itemsData" }
       }}
      ]).pretty()
    

    Hope, this was helpful.