Ashley
Ashley

Reputation: 1489

How to return array index with $indexOfArray

I have the following document structure in Mongo:

{
    "participantIdentities": [
        {
            "player": {
                "summonerName": "Summ1",
                "otherData": "Whatever"
            },
            "participantId": 1
        },
        {
            "player": {
                "summonerName": "Summ2",
                "otherData": "Whatever2"
            },
            "participantId": 2
        }
    ]
}

And I am trying to return the index of one of the elements, so I can then pass that to the next part of the pipeline but it's throwing an error.

Code:

db.match.aggregate(
    [
        {
            "$project": {
                "matchedIndex": {
                    "$indexOfArray": [
                        "$participantIdentities", {"$player.summonerName": {$eq: "Summ2"}}
                    ]
                }
            }
        }
    ]
)

Error:

"ok" : 0,
"errmsg" : "Unrecognized expression '$participantIdentities.player.summonerName'",
"code" : 168,
"codeName" : "InvalidPipelineOperator"

I'm not sure what I'm doing wrong, I'm not sure if querying the current array's elements is supported which might be the issue?

In the example above, I'd want it to return the second element's array index (where summonerName is Summ2) i.e. {"matchedIndex": 1}. What am I doing wrong?

Upvotes: 6

Views: 6053

Answers (1)

Neil Lunn
Neil Lunn

Reputation: 151122

If you look at the usage it actually tells you. That the "array" is the first argument and the second argument is a "search expression" that must produce a value for an equality check.

So rather than write the expression to "test an element equality" you instead "point to the element in the array to test". Which means notating like "$participantIdentities.player.summonerName" in order to simply test against the "name" properties as a converted array:

db.match.aggregate([
 { "$project": {
   "matchedIndex": {
     "$indexOfArray": [
       "$participantIdentities.player.summonerName",
       "Summ2"
     ]
   }
 }}
])

The notation basically takes the source array and makes it appear as follows for comparison:

[ "Summ1", "Summ2" ]

Or if you prefer, then think of the above as with the JavaScript equivalent idiom, using .map() and indexOf()

participantIdentities.map( p => p.player.summonerName ).indexOf("Summ2")

Which is the same thing from a practical standpoint. So even

"$participantIdentities.player.summonerName"

is essentially "shorthand" for using the $map operator of MongoDB.

And then in comparison, since the "second index" which is n-1 or 1 is the match, then that value is returned.

Upvotes: 12

Related Questions