67

I'm aware of the $in operator, which appears to search for an item's presence in array, but I only want to find a match if the item is in the first position in an array.

For instance:

{
    "_id" : ObjectId("0"),
    "imgs" : [
        "http://foo.jpg",
        "http://bar.jpg",
        "http://moo.jpg",
        ]
},
{
    "_id" : ObjectId("1"),
    "imgs" : [
        "http://bar.jpg",
        "http://foo.jpg",
        "http://moo.jpg",
        ]
}

I'm looking for a query akin to:

db.products.find({"imgs[0]": "http://foo.jpg"})

This would/should return the ObjectId("0") but not ObjectId("1"), as it's only checking against the first image in the array.

How can this be achieved? I'm aware I could just create a separate field which contains a single string for firstImg but that's not really what I'm after here.

JVG
  • 20,198
  • 47
  • 132
  • 210

2 Answers2

124

I believe you want imgs.0. eg, given your example document, you want to say: db.products.find({"imgs.0": "http://foo.jpg"})

Be aware that referencing array indexes only works for the first-level array. Mongo doesn't support searching array indexes any deeper.

poundifdef
  • 18,726
  • 23
  • 95
  • 134
  • Great. By first-level array do you mean that it won't work on arrays within arrays/arrays within objects> – JVG Nov 11 '13 at 05:38
  • 17
    The following would not work: `{"images.0.5": "foo.jpg"}` `{"images.0.aliases.3": "foo.jpg"}` The following will work: `{"images.2.name": "foo.jpg"}` That is, multiple levels of nesting work, but only one level of "array-indexing" is supported by Mongo. – poundifdef Nov 11 '13 at 05:50
  • 2
    do you have any reference for the "only first-level array" part? – Sebastien Lorber Jun 01 '15 at 12:52
  • 2
    At least on MongoDB version 3.2.6, there is no problem with nested indices. i.e. on the document: `{a: [{b: [1,2]}, [3,4]]}`, the query `db.testcollection.find({"a.0.b.1": 1})` works correctly. – GoogieK Jul 27 '16 at 14:29
  • 2
    See also: [`$elemMatch`](https://docs.mongodb.com/manual/reference/operator/query/elemMatch/#op._S_elemMatch): `db.products.find({"imgs": {$elemMatch: {"0": "http://foo.jpg"}}})` – Udi May 04 '17 at 10:44
  • @Udi, do you know if that usage is deprecated for v4.2? I couldn't get it to work – Jinglesting Sep 09 '19 at 12:36
15

You can use dot notation for array indexes:

db.products.find({"imgs.0": "http://foo.jpg"})

Here is an excerpt from the relevant documentation for dot notation.

MongoDB uses the dot notation to access the elements of an array and to access the fields of a subdocument.

To access an element of an array by the zero-based index position, concatenate the array name with the dot (.) and zero-based index position, and enclose in quotes:

'<array>.<index>'

Additionally, here is a link to the relevant array documentation.

Community
  • 1
  • 1
Lix
  • 47,311
  • 12
  • 103
  • 131