inolasco
inolasco

Reputation: 694

MongoDB aggregation: Project separate document fields into a single array field

I have a document like this:

{fax: '8135551234', cellphone: '8134441234'}

Is there a way to project (without a group stage) this document into this:

{
    phones: [{
        type: 'fax',
        number: '8135551234'
    }, {
        type: 'cellphone',
        number: '8134441234'
    }]
}

I could probably use a group stage operator for this, but I'd rather not if there's any other way, because my query also projects several other fields, all of which would require a $first just for the group stage.

Hope that's clear. Thanks in advance!

Upvotes: 3

Views: 3108

Answers (1)

Neil Lunn
Neil Lunn

Reputation: 151170

MongoDB 2.6 Introduces the the $map operator which is an array transformation operator which can be used to do exactly this:

db.phones.aggregate([
    { "$project": {
        "phones": { "$map": {
            "input": { "$literal": ["fax","cellphone"] },
            "as": "el",
            "in": {
                "type": "$$el",
                "number": { "$cond": [
                     { "$eq": [ "$$el", "fax" ] },
                     "$fax",
                     "$cellphone"
                 ]}
             }
        }}
    }}
])

So your document now looks exactly like you want. The trick of course to to create a new array with members "fax" and "cellphone", then transform that array with the new document fields by matching those values.

Of course you can also do this in earlier versions using $unwind and $group in a similar fashion, but just not as efficiently:

db.phones.aggregate([
    { "$project": {
        "type": { "$const": ["fax","cellphone"] },
        "fax": 1,
        "cellphone": 1
    }},
    { "$unwind": "$type" },
    { "$group": {
        "_id": "_id",
        "phones": { "$push": { 
            "type": "$type",
            "number": { "$cond": [
                { "$eq": [ "$type", "fax" ] },
                "$fax",
                "$cellphone"
            ]}
        }}
    }}
])

Of course it can be argued that unless you are doing some sort of aggregation then you may as well just post process the collection results in code. But this is an alternate way to do that.

Upvotes: 4

Related Questions