Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Concatenate array elements in MongoDB 3.4 with Aggregation Framework

What I have :

{ "_id" : ObjectId("577dc9d61a0b7e0a40499f90"), "equ" : 123456, "key" : "p" }
{ "_id" : ObjectId("577c789b1a0b7e0a403f1b52"), "equ" : 123456, "key" : "r" }
{ "_id" : ObjectId("577b27481a0b7e0a4033965a"), "equ" : 123456, "key" : "r" }
{ "_id" : ObjectId("5779d6111a0b7e0a40282dc7"), "equ" : 123456, "key" : "o" }

What I want :

{ "_id" : ObjectId("5779d6111a0b7e0a40282dc7"), "equ" : 123456, "keys" : "prro" }

What I tried :

db.table.aggregate([{"$group":{"_id":0, "keys":{"$push":"$key"}}}]) returns an array and not a string:

{"_id":0, "keys":["p","r","r","o"]}

Do you have any idea?

like image 241
hotips Avatar asked Jul 07 '16 13:07

hotips


People also ask

How do I concatenate strings in MongoDB?

Concatenates strings and returns the concatenated string. $concat has the following syntax: { $concat: [ <expression1>, <expression2>, ... ] } The arguments can be any valid expression as long as they resolve to strings.

How do I add elements to an array in MongoDB?

If the value is an array, $push appends the whole array as a single element. To add each element of the value separately, use the $each modifier with $push . For an example, see Append a Value to Arrays in Multiple Documents. For a list of modifiers available for $push , see Modifiers.

Which aggregation method is preferred for use by MongoDB?

The pipeline provides efficient data aggregation using native operations within MongoDB, and is the preferred method for data aggregation in MongoDB. The aggregation pipeline can operate on a sharded collection.

Is aggregation a framework in MongoDB?

The MongoDB aggregation framework is an extremely powerful set of tools. The processing is done on the server itself which results in less data being sent over the network.


1 Answers

TL; DR

Use this aggregation pipeline:

db.col.aggregate([
    {$group: {_id: "$equ", last: {$last: "$_id"}, keys: {$push: "$key"}}},
    {
        $project: {
            equ: "$_id",
            _id: "$last",
            keys: {
                $reduce: {
                    input: "$keys",
                    initialValue: "",
                    in: {$concat: ["$$value", "$$this"]}
                }
            }
        }
    }
])

More details

First you should group the documents based on the equ value and also maintain an array of keys along with the _id of the last group member:

var groupByEqu = {
    $group: {
        _id: "$equ",
        last: {$last: "$_id"},
        keys: {$push: "$key"}
    }
}

Just applying this pipeline operation would result in:

{ 
    "_id" : 123456, 
    "last" : ObjectId("5779d6111a0b7e0a40282dc7"), 
    "keys" : [ "p", "r", "r", "o" ] 
}

You should use a Projection to transform the preceding document into your desired one. The first two transformations are trivial. For joining the array elements you can use the new $reduce operator:

var project = {
    $project: {
        equ: "$_id",
        _id: "$last",
        keys: {
            $reduce: {
                input: "$keys",
                initialValue: "",
                in: {$concat: ["$$value", "$$this"]}
            }
        }
    }
} 

Applying these two pipeline operations would give you the desired result:

db.col.aggregate([groupByEqu, project])

Which is:

{ 
    "equ" : 123456, 
    "_id" : ObjectId("5779d6111a0b7e0a40282dc7"), 
    "keys" : "prro"
}
like image 136
Ali Dehghani Avatar answered Nov 15 '22 07:11

Ali Dehghani