Reputation: 415
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.
Upvotes: 4
Views: 4049
Reputation: 151112
Depending on the available version of MongoDB you have there are different approaches:
$indexOfArray
- MongoDB 3.4The 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.2Going 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") } }
])
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.
Upvotes: 6