Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get index of given element in array field in MongoDB

Think of this MongoDB document:

{_id:123, "food":[ "apple", "banana", "mango" ]}

Question: How to get the position of mango in food?

The query should return 2 in above, and don't return the whole document.

Please kindly show the working query.

like image 787
James Yang Avatar asked Oct 13 '15 10:10

James Yang


People also ask

How do I index an array in MongoDB?

To index a field that holds an array value, MongoDB creates an index key for each element in the array. These multikey indexes support efficient queries against array fields. Multikey indexes can be constructed over arrays that hold both scalar values [1] (e.g. strings, numbers) and nested documents.

How do I pull an element from an array in MongoDB?

To remove an element, update, and use $pull in MongoDB. The $pull operator removes from an existing array all instances of a value or values that match a specified condition.

How do I see indexes in MongoDB?

Finding indexes You can find all the available indexes in a MongoDB collection by using the getIndexes method. This will return all the indexes in a specific collection. Result: The output contains the default _id index and the user-created index student name index.

Which index is used to index the content stored in arrays in MongoDB?

MongoDB uses multikey indexes to index the content stored in arrays. If you index a field that holds an array value, MongoDB creates separate index entries for every element of the array. These multikey indexes allow queries to select documents that contain arrays by matching on element or elements of the arrays.


2 Answers

Starting from MongoDB version 3.4 we can use the $indexOfArray operator to return the index at which a given element can be found in the array.

$indexOfArray takes three arguments. The first is the name of the array field prefixed with $ sign.

The second is the element and the third optional is the index to start the search at. $indexOfArray returns the first index at which the element is found if the index to start the search at is not specified.


Demo:

> db.collection.insertOne( { "_id" : 123, "food": [ "apple", "mango", "banana", "mango" ] } )
{ "acknowledged" : true, "insertedId" : 123 }
> db.collection.aggregate( [ { "$project": { "matchedIndex": { "$indexOfArray": [ "$food", "mango" ] } } } ] )
{ "_id" : 123, "matchedIndex" : 1 }
> db.collection.aggregate( [ { "$project": { "matchedIndex": { "$indexOfArray": [ "$food", "mango", 2 ] } } } ] )
{ "_id" : 123, "matchedIndex" : 3 }
> db.collection.aggregate( [ { "$project": { "matchedIndex": { "$indexOfArray": [ "$food", "apricot" ] } } } ]  )
{ "_id" : 123, "matchedIndex" : -1 }
like image 182
styvane Avatar answered Sep 18 '22 09:09

styvane


There really is no other way ( "server side" ) than using mapReduce:

db.collection.mapReduce(
    function() {
        emit(this._id, this.food.indexOf("mango"));
    },
    function() {},   // reducer never gets called since all _id is unique
    { 
        "out": { "inline": 1 },
        "query": { "food": "mango" }
    }
)

It is the only thing that will return something else in a modified form other than the document itself, as well as using the needed JavaScript evaluation in order to determine the answer,

There is unfortunately no "native" operator that will do this.

Unless you need this for real aggregation purposes, then it is better to just do a similar "array index match" in native code in your client when dealing on a "per document" basis.

like image 37
Blakes Seven Avatar answered Sep 18 '22 09:09

Blakes Seven