Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Projections in Mongodb nested arrays

Tags:

mongodb

nested

I have a heavily nested Document in Mongodb that follows this order:

site -> rooms -> ups -> batteryStrings -> batteries.

I'm trying to return only the matching batteryStrings and its batteries by the batteryString _id field.

db.getCollection('sites').find({
    "rooms.ups.batteryStrings._id": ObjectId("55dc967efefd4e6a14332019")
    }, {
        "rooms.ups.batteryStrings.batteries.$": 1,
        "siteName": 1
    }
)

I get the following which has 2 batteryStrings. I would only like to return the 2nd batteryString (highlighted in yellow), along with its batteries.

enter image description here

I was originally trying this but got the same results:

db.getCollection('sites').find({
"rooms.ups.batteryStrings._id": ObjectId("55dc967efefd4e6a14332019")
}, {
    "rooms.ups.batteryStrings.$": 1,
    "siteName": 1
})
like image 777
Ryan Gill Avatar asked Aug 28 '15 15:08

Ryan Gill


1 Answers

You could try the aggregation framework to achieve the desired results. The pipeline would need to make use of an initial $match operator that filters out the unwanted documents to get into the pipeline. Once you get the desired documents you would run multiple $unwind operators on the array fields to output a document for each element in the array fields for use in the next pipeline step. The following pipeline will need to filter the other documents from the deconstructed arrays using $match operator to then give you the required document. The last step of the pipeline, $project, then reshapes each document in the stream, such as by adding new fields or removing existing fields. For each input document, outputs one document. Thus the following pipeline will give you the result:

db.sites.aggregate([
    {
        "$match": {
            "rooms.ups.batteryStrings._id": ObjectId("55dc967efefd4e6a14332019")
        }
    },
    { "$unwind": "$rooms" },
    { "$unwind": "$rooms.ups" },
    { "$unwind": "$rooms.ups.batteryStrings" },
    {
        "$match": {
            "rooms.ups.batteryStrings._id": ObjectId("55dc967efefd4e6a14332019")
        }
    },
    {
        "$project": {
            "siteName": 1,
            "batteryStrings": "$rooms.ups.batteryStrings"
        }
    }
])

Running the pipeline operation would produce the result:

/* 0 */
{
    "result" : [ 
        {
            "_id" : ObjectId("5613c98a645a64b1a70af2c1"),
            "siteName" : "OGG",
            "batteryStrings" : {
                "name" : "String 1",
                "ctrlId" : "bmstest11",
                "_id" : ObjectId("55dc967efefd4e6a14332019"),
                "batteries" : [ 
                    {
                        "name" : "String 2a",
                        "ctrlId" : "bmstest11",
                        "_id" : ObjectId("55e67b28010000880ca4c045")
                    }, 
                    {
                        "name" : "String 2b",
                        "ctrlId" : "bmstest11",
                        "_id" : ObjectId("55ea1b520100006d004e602a")
                    }, 
                    {
                        "name" : "String 2c",
                        "ctrlId" : "bmstest11",
                        "_id" : ObjectId("55ea1b520100006d004e602b")
                    }
                ]
            }
        }
    ],
    "ok" : 1
}
like image 70
chridam Avatar answered Oct 01 '22 13:10

chridam