42

As part of my document in MongoDB I'm storing an array of objects. How can I query it for only the 4th element of the array for example? So I don't want the get the entire array out, just the 4th element.

styvane
  • 59,869
  • 19
  • 150
  • 156
mck
  • 2,040
  • 3
  • 19
  • 29
  • Or perhaps [Reaching Objects Array Element by Position](http://www.mongodb.org/display/DOCS/Dot+Notation+%28Reaching+into+Objects%29#DotNotation%28ReachingintoObjects%29-ArrayElementbyPosition) – calmrat Oct 09 '12 at 08:58

3 Answers3

71

Use $slice.

db.foo.find({ bar : "xyz" } , { my_array : { $slice : [n , 1] } } )

will retrieve the nth element of the array "my_array" of all documents in the foo collection where bar = "xyz".

Some other examples from the MongoDB documentation:

db.posts.find({}, {comments:{$slice: 5}}) // first 5 comments
db.posts.find({}, {comments:{$slice: -5}}) // last 5 comments
db.posts.find({}, {comments:{$slice: [20, 10]}}) // skip 20, limit 10
db.posts.find({}, {comments:{$slice: [-20, 10]}}) // 20 from end, limit 10

Which you can read here: http://www.mongodb.org/display/DOCS/Retrieving+a+Subset+of+Fields

Russell
  • 12,261
  • 4
  • 52
  • 75
  • 2
    small correction to your line " db.foo.find({ bar : "xyz" } , { my_array : { $slice : [n , 1] } } ) will retrieve the nth element of the array "my_array" of all documents in the foo collection where bar = "xyz". " i think this will give the (n+1)th element from the array my_array because $slice : [n, 1] , means skip n , limit 1 , so it will return the n+1 th element from the array – Bravo Jul 11 '14 at 21:01
19

You can use the $arrayElemAt operator new in MongoDB 3.2 to return the element at the specified array index.


Demo:

A collection named baskets contains documents that look like this:

{
    "_id" : ObjectId("578f326f6db61a299a383c5a"),
    "fruits" : [
        "apple",
        "mango",
        "banana",
        "apricot",
        "cherry"
    ]
}

The following query return the element at index -2 (second element) in the "fruits" array.

db.baskets.aggregate(
    [
        { "$project": { "matched": { "$arrayElemAt": [ "$fruits", 1 ] } } } 
    ] 
)

which produces

{ 
    "_id" : ObjectId("578f326f6db61a299a383c5a"), 
    "matched" : "mango" 
}

And the following query the element before the last element in the array; thus the element at index -2

db.baskets.aggregate(
    [
        { "$project": { "matched": { "$arrayElemAt": [ "$fruits", -2 ] } } } 
    ] 
)

which yields:

{ 
    "_id" : ObjectId("578f326f6db61a299a383c5a"), 
    "matched" : "apricot" 
}
styvane
  • 59,869
  • 19
  • 150
  • 156
  • For me, this is the Accepted Answer! I needed a way to swap between 2 elements in an array but couldn't find how to access an element by index upon an *update*. This $arrayElemAt operator saved me a ton. – Tal Kohavy Jul 06 '22 at 17:07
9

Another way to do this is to use the update array syntax. Here, contribs.1 sets the second element in the contribs array to have value ALGOL 58 (Taken from the manual page on update syntax)

db.bios.update(
   { _id: 1 },
   { $set: { 'contribs.1': 'ALGOL 58' } }
)
Jonathan
  • 8,453
  • 9
  • 51
  • 74
Eskoala
  • 312
  • 2
  • 4