Reputation: 1181
How can I get and return the first element in an array using a Mongo aggregation?
I tried using this code:
db.my_collection.aggregate([
{ $project: {
resp : { my_field: { $slice: 1 } }
}}
])
but I get the following error:
uncaught exception: aggregate failed: {
"errmsg" : "exception: invalid operator '$slice'",
"code" : 15999,
"ok" : 0
}
Note that 'my_field'
is an array of 4 elements, and I only need to return the first element.
Upvotes: 31
Views: 38241
Reputation: 15234
Since 3.2, we can use $arrayElemAt
to get the first element in an array
db.my_collection.aggregate([
{ $project: {
resp : { $arrayElemAt: ['$my_field',0] }
}}
])
Upvotes: 28
Reputation: 61646
Starting Mongo 4.4
, the aggregation operator $first
can be used to access the first element of an array:
// { "my_field": ["A", "B", "C"] }
// { "my_field": ["D"] }
db.my_collection.aggregate([
{ $project: { resp: { $first: "$my_field" } } }
])
// { "resp" : "A" }
// { "resp" : "D" }
Upvotes: 2
Reputation: 1569
Mongo 3.1.6 onwards,
db.my_collection.aggregate([
{
"$project": {
"newArray" : { "$slice" : [ "$oldarray" , 0, 1 ] }
}
}
])
where 0
is the start index and 1
is the number of elements to slice
Upvotes: 0
Reputation: 49152
The $slice operator is scheduled to be made available in the $project operation in Mongo 3.1.4, according to this ticket: https://jira.mongodb.org/browse/SERVER-6074
This will make the problem go away.
This version is currently only a developer release and is not yet stable (as of July 2015). Expect this around October/November time.
Upvotes: 1
Reputation: 19700
Currently, the $slice
operator is unavailable in the the $project
operation, of the aggregation pipeline.
So what you could do is,
First $unwind
, the my_field
array, and then group them together and take the $first
element of the group.
db.my_collection.aggregate([
{$unwind:"$my_field"},
{$group:{"_id":"$_id","resp":{$first:"$my_field"}}},
{$project:{"_id":0,"resp":1}}
])
Or using the find()
command, where you could make use of the $slice operator in the projection
part.
db.my_collection.find({},{"my_field":{$slice:1}})
Update: based on your comments, Say you want only the second
item in an array, for the record with an id, id
.
var field = 2;
var id = ObjectId("...");
Then, the below aggregation command gives you the 2nd item in the my_field
array of the record with the _id
, id
.
db.my_collection.aggregate([
{$match:{"_id":id}},
{$unwind:"$my_field"},
{$skip:field-1},
{$limit:1}
])
The above logic cannot be applied for more a record, since it would involve a $group
, operator after $unwind
. The $group
operator produces a single record for all the records in that particular group making the $limit
or $skip
operators applied in the later stages to be ineffective.
A small variation on the find()
query above would yield you the expected result as well.
db.my_collection.find({},{"my_field":{$slice:[field-1,1]}})
Apart from these, there is always a way to do it in the client side, though a bit costly if the number of records is very large:
var field = 2;
db.my_collection.find().map(function(doc){
return doc.my_field[field-1];
})
Choosing from the above options depends upon your data size and app design.
Upvotes: 10