简体   繁体   中英

How to find documents in MongoDb matching a field and subdocument field that are in an array

The document structure is as follows:

{
"_id" : "V001-99999999",
"vendor_number" : "V001",
"created_time" : ISODate("2016-04-26T22:15:34Z"),
"updated_time" : ISODate("2016-06-07T21:45:46.413Z"),
"items" : [
    {
        "sku" : "99999999-1",
        "status" : "ACTIVE",
        "listing_status" : "LIVE",
        "inventory" : 10,
        "created_time" : ISODate("2016-05-14T22:15:34Z"),
        "updated_time" : ISODate("2016-05-14T20:42:21.753Z"),
    },
    {
        "sku" : "99999999-2",
        "status" : "INACTIVE",
        "listing_status" : "LIVE",
        "inventory" : 10,
        "created_time" : ISODate("2016-04-26T22:15:34Z"),
        "updated_time" : ISODate("2016-06-06T20:42:21.753Z"),
    }
]

}

I want to obtain the sku from the item, the conditions are:

1) "vendor_number" = "XXX"

2) items.status = "ACTIVE" AND items.updated_time < [given_date]

Result example:

"sku" : "99999999-2" 

or csv:

"sku","99999999-2"

Thank you for your support.

This should be what you want. Although I'm assuming you wanted "status": "active" ?

db.getCollection('collection').aggregate([

 { $match: { "vendor_number": "XXXX" } },

 { $project: {
     "items": {
         $filter: {
            input: "$items",
            as: "item",
            cond: { $eq: ["$$item.status", "ACTIVE"] } // or maybe ["$$item.listing_status", "LIVE"] ?
         }
      }
    }
  },     

 { $project: { "items.sku": true } }

])

I love using aggregation to manipulate stuff. It's great all the things you can do with it. So here's what's going on:

The first part is simple. The $match step in the aggregation pipeline says just give me documents where vendor_number is "XXXX".

The next part is a bit hairy. The first projection step creates a new field, called "items", I could have called it "results" or "bob" if I wanted to. The $filter specifies which items should go into this new field. The new "items" field will be an array that will have all the results from the previous items field, hence the input: "$items" , where you're using the keyword "item" to represent each input item that comes into the filter. Next, the condition says, for each item, only put it in my new "items" array if the item's status is "ACTIVE". You can change it to ["$$items.listing_status", "LIVE"] if that's what you needed. All of this will pretty much give you you're result.

The last project just get's rid of all other fields except for items.sku in each element in the new "items" array.

Hope this help. Play around with it and see what else you can do with the collection and aggregation. Let me know if you need any more clarification. If you haven't used aggregation before, take a look at the aggregation docs and the list of pipeline operators you can use with aggregation. Pretty handy tool.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM