Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 375
Ashley Avatar asked Aug 15 '17 11:08

Ashley


1 Answers

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.

like image 139
Neil Lunn Avatar answered Nov 15 '22 07:11

Neil Lunn