4

Is there a way to get index in aggregate pipeline, I have a result from long aggreagte query

[
    {
        "_id": "59ed949227ec482044b2671e",
        "points": 300,
        "fan_detail": [
            {
                "_id": "59ed949227ec482044b2671e",
                "name": "mila   ",
                "email": "[email protected] ",
                "password": "$2a$10$J0.KfwVnZkaimxj/BiqGW.D40qXhvrDA952VV8x.xdefjNADaxnSW",
                "username": "mila  0321",
                "updated_at": "2017-10-23T07:04:50.004Z",
                "created_at": "2017-10-23T07:04:50.004Z",
                "celebrity_request_status": 0,
                "push_notification": [],
                "fan_array": [],
                "fanLength": 0,
                "celeb_bio": null,
                "is_admin": 0,
                "is_blocked": 2,
                "notification_setting": [
                    1,
                    2,
                    3,
                    4,
                    5,
                    6,
                    7
                ],
                "total_stars": 0,
                "total_points": 134800,
                "user_type": 2,
                "poster_pic": null,
                "profile_pic": "1508742289662.jpg",
                "facebook_id": "alistnvU79vcc81PLW9o",
                "is_user_active": 1,
                "is_username_selected": "false",
                "__v": 0
            }
        ]
    }
],

so I want to find the index of _id in aggregate query and above array can contain 100s of object in it.

1 Answer 1

6

Depending on the available version of MongoDB you have there are different approaches:

$indexOfArray - MongoDB 3.4

The best operator for this is simply $indexOfArray where you have it available. The name says it all really:

Model.aggregate([
  { "$match": { "fan_detail._id": mongoose.Types.ObjectId("59ed949227ec482044b2671e") } },

  { "$addFields": { 
    "fanIndex": {
      "$indexOfArray": [
        "$fan_detail._id",
        mongoose.Types.ObjectId("59ed949227ec482044b2671e")
      ]
    }
  }}
])

$unwind with includeArrayIndex - MongoDB 3.2

Going back a version in releases, you can get the index from the array from the syntax of $unwind. But this does require you to $unwind the array:

Model.aggregate([
  { "$match": { "fan_detail._id": mongoose.Types.ObjectId("59ed949227ec482044b2671e") } },
  { "$unwind": { "path": "$fan_detail", "includeArrayIndex": true } },
  { "$match": { "fan_detail._id": mongoose.Types.ObjectId("59ed949227ec482044b2671e") } }
])

mapReduce - Earlier versions

Earlier versions of MongoDB to 3.2 don't have a way of returning an array index in an aggregation pipeline. So if you want the matched index instead of all the data, then you use mapReduce instead:

Model.mapReduce({
  map: function() {
    emit(
      this._id,
      this['fan_detail']
        .map( f => f._id.valueOf() )
        .indexOf("59ed949227ec482044b2671e") 
    )
  },
  reduce: function() {},
  query: { "fan_detail._id": mongoose.Types.ObjectId("59ed949227ec482044b2671e") }
})

In all cases we essentially "query" for the presence of the element "somewhere" in the array beforehand. The "indexOf" variants would return -1 where nothing was found otherwise.

Also $addFields is here just for example. If it's your real intent to not return the array of 100's of items, then you're probably using $project or other output anyway.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for the answer and its correct yeah I am using pagination as well to limit the 100s records
@IrfanKhan Well there is also $slice if you were just simply looking to do that. "Pagination of arrays" is why that has been around since very early releases of MongoDB.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.