Sergio
Sergio

Reputation: 23

How to get arrays on output from MongoDB aggregate

I have documents in MongoDB, like so:

{
    "_id" : ObjectId("5a748c8b178227d602ec9ce8"),
    "dateHour" : ISODate("2018-02-02T16:00:00.000Z"),
    "data" : [ 
        {
            "date" : ISODate("2018-02-02T16:06:35.033Z"),
            "cap" : 437105726836.0
        }, 
        {
            "date" : ISODate("2018-02-02T16:09:25.127Z"),
            "cap" : 437316498502.0
        },
        ...
    ]
}

Using aggregate method (in NodeJS):

db.getCollection('hourly').aggregate([
    {$match: {}}, 
    {$unwind: "$data"}, 
    {$project: {_id: 0, date: "$data.date", cap: "$data.cap" } }
])

I get output like:

[
    {
        "date" : ISODate("2018-02-02T16:06:35.033Z"),
        "cap" : 437105726836.0
    },
    {
        "date" : ISODate("2018-02-02T16:09:25.127Z"),
        "cap" : 437316498502.0
    }
]

QUESTION: What is the most effective way to get output like so:

[
    [ISODate("2018-02-02T16:06:35.033Z"), 437105726836.0],
    [ISODate("2018-02-02T16:09:25.127Z"), 437316498502.0]
]

?

I can simply add .map(function(item) {return [item.date, item.cap]}) but is this most effective way when working with huge amount of data?

Upvotes: 2

Views: 5180

Answers (3)

Saravana
Saravana

Reputation: 12817

try $project with $map or $reduce

$map

db.col.aggregate(
    [
        {$project : {
            _id : 0, 
            data : {$map : {input : "$data", as : "d", in : ["$$d.date", "$$d.cap"]}}
            }
        }
    ]
)

$reduce

db.col.aggregate(
    [
        {$project : {
            _id : 0, 
                data : {$reduce : {input : "$data", initialValue : [], in : {$concatArrays : ["$$value", [["$$this.date", "$$this.cap"]]]}}}
            }
        }
    ]
).pretty()

output

{
    "data" : [
        [
            ISODate("2018-02-02T16:06:35.033Z"),
            437105726836
        ],
        [
            ISODate("2018-02-02T16:09:25.127Z"),
            437316498502
        ]
    ]
}

Upvotes: 2

Jeff Matthews
Jeff Matthews

Reputation: 592

It's in the projection. Try this:

db.getCollection('hourly').aggregate([
   {$match: {}}, 
   {$unwind: "$data"}, 
   {$project: {_id: 0, date: ["$data.date", "$data.cap"] } }
]);

Just in case my syntax is a little off, here is MongoDb documentation to project a new array.

I don't see why you need aggregate.

Why not:

db.getCollection('hourly').find({}, {data: 1}, (err, results) => {
   // manage results here.
});

Upvotes: 0

Kevin Smith
Kevin Smith

Reputation: 14436

The root has to be a document, proof:

db.test.aggregate([
    {$unwind: "$data"}, 
    { $replaceRoot: { newRoot: ["$data.date", "$data.cap"] } }
]);
assert: command failed: {
        "ok" : 0,
        "errmsg" : "'newRoot' expression must evaluate to an object, but resulting value was: [null, null]. Type of resulting value: 'array'. Input document: {date: 2018-02-02T16:06:35.033Z, cap: 4.37106e+11}",
        "code" : 40228,
        "codeName" : "Location40228"
} : aggregate failed

You could, however, project it into an array within a document:

> db.test.aggregate([
...     {$unwind: "$data"},
... { $replaceRoot: { newRoot: {a:["$data.date", "$data.cap"] } }}
... ])
{ "a" : [ ISODate("2018-02-02T16:06:35.033Z"), 437105726836 ] }
{ "a" : [ ISODate("2018-02-02T16:09:25.127Z"), 437316498502 ] }

Upvotes: 0

Related Questions