MongoDB 3.4 - get array of subdocuments without root document
Asked Answered
D

2

7

I have a projects collection with documents such as this:

{
        "_id" : ObjectId("589eff3fee3d13019843f55a"),
        "name" : "Project A",
        "desc" : "test",
        "numofvms" : 0,
        "templates" : [
                {
                        "_id" : ObjectId("589e4c14ee3d131bac8b403c")
                },
                {
                        "_id" : ObjectId("589e4c1dee3d131bac8b403d")
                }
        ],
        "nodes" : [
                {
                        "_id" : ObjectId("589eff8f2bb59057c3f9b89d"),
                        "name" : "Node A"
                },
                {
                        "_id" : ObjectId("589eff962bb59057c3f9b89e"),
                        "name" : "Node B"
                },
                {
                        "_id" : ObjectId("589eff982bb59057c3f9b89f"),
                        "name" : "Node C"
                },
                {
                        "_id" : ObjectId("589eff9a2bb59057c3f9b8a0"),
                        "name" : "Node D"
                }
        ],
        "links" : [ ]
}

I try to receive the array of subdocuments (nodes field) for a given document (project), but without the root document. The result should look like this:

[
        {
                "_id" : ObjectId("589eff8f2bb59057c3f9b89d"),
                "name" : "Node A"
        },
        {
                "_id" : ObjectId("589eff962bb59057c3f9b89e"),
                "name" : "Node B"
        },
        {
                "_id" : ObjectId("589eff982bb59057c3f9b89f"),
                "name" : "Node C"
        },
        {
                "_id" : ObjectId("589eff9a2bb59057c3f9b8a0"),
                "name" : "Node D"
        }
]

I tried different approaches like the one below but could not get rid of the root document:

> db.projects.find({_id: ObjectId("589eff3fee3d13019843f55a")}, { "nodes": 1, _id: 0 }).pretty()
{
        "nodes" : [
                {
                        "_id" : ObjectId("589eff8f2bb59057c3f9b89d"),
                        "name" : "Node A"
                },
                {
                        "_id" : ObjectId("589eff962bb59057c3f9b89e"),
                        "name" : "Node B"
                },
                {
                        "_id" : ObjectId("589eff982bb59057c3f9b89f"),
                        "name" : "Node C"
                },
                {
                        "_id" : ObjectId("589eff9a2bb59057c3f9b8a0"),
                        "name" : "Node D"
                }
        ]
}

Can this be achieved directly in the query or do I have to extract the array manually in my application?

Density answered 11/2, 2017 at 12:44 Comment(0)
A
8

Try this:

db.collection.aggregate([
    {
        $unwind: '$nodes'
    },
    {
        $match: {_id: ObjectId("589eff3fee3d13019843f55a") }
    },
    {
        $replaceRoot: { newRoot: "$nodes" }
    }
]).toArray();

And you will get

[
    {
        "_id" : ObjectId("589eff8f2bb59057c3f9b89d"),
        "name" : "Node A"
    },
    {
        "_id" : ObjectId("589eff962bb59057c3f9b89e"),
        "name" : "Node B"
    },
    {
        "_id" : ObjectId("589eff982bb59057c3f9b89f"),
        "name" : "Node C"
    },
    {
        "_id" : ObjectId("589eff9a2bb59057c3f9b8a0"),
        "name" : "Node D"
    }
]

$unwind operator is to deconstruct nodes field from the input documents to output a document for each element.

And then use the $replaceRoot stage to promote the nodes document to the top level, discarding the current top level fields.

Hope this helps.

Aeschines answered 12/2, 2017 at 4:39 Comment(0)
S
2

Here is how you can do this with aggregation (Mongo v3.4+):

db.projects.aggregate([
	{$match: {_id: ObjectId("589eff3fee3d13019843f55a")}},
	{$unwind: '$nodes'},
	{$replaceRoot: { newRoot: "$nodes"}}
]).toArray();

Check out the docs.

Sacramental answered 12/2, 2017 at 5:8 Comment(1)
Your code snippet doesn't seem to be working, but your answer is technically correct.Nonsmoker

© 2022 - 2024 — McMap. All rights reserved.