Cant able to find subdocument counts based on condition - node.js

I have a schema in which it has some fields..
i am not able to find query for this, i tried $group but was not able to find results
collection: tasks
{
"_id" : ObjectId("5a475ee4b342fa03e71192bd"),
"title" : "Some Title",
"assignedUsers" : [
{
"_id" : ObjectId("5a47386ee4788102e530f60d"),
"name" : "Sam",
"status" : "Unconfirmed"
},
{
"_id" : ObjectId("5a473878e4788102e530f60f"),
"name" : "Ricky",
"status" : "Rejected"
}
{
"_id" : ObjectId("5a47388be4788102e530f611"),
"name" : "Niel",
"status" : "Unconfirmed"
},
{
"_id" : ObjectId("5a47388be4788102e530f611"),
"name" : "ABC",
"status" : "Unconfirmed"
},
{
"_id" : ObjectId("5a473892e4788102e530f612"),
"name" : "Rocky",
"status" : "Rejected"
}
]
}
Result should contain
Unconfirmed=3
Rejected=2
Thanks

Use below query,
db.coll3.aggregate([{
$unwind: '$assignedUsers'
}, {
$group: {
_id: '$assignedUsers.status',
'count': {
$sum: 1
}
}
}
])
If you want to query against a particular document make sure, you use a $match as first stage and then use the other 2 $unwind and $group.
You would get result as
{ "_id" : "Rejected", "count" : 2 }
{ "_id" : "Unconfirmed", "count" : 3 }
Hope this helps.

Related

Update double nested emedded documents in mongodb nodejs without using number index

I want to update Itinirary which is embedded subdocument inside the
packages which itself is a embedded document.I tried using index and
was successful like this :
"$set":{'packages.$.itinerary.0.to': "kausaltar"}
but I don't want to use index like 0,1 in itinerary update.Please can you help me.
My JSON schema is like this :
{
"_id" : ObjectId("5e1ca76b9f96d17c449de177"),
"org_id" : "22222222222",
"packages" : [
{
"_id" : ObjectId("5e1ca76b9f96d17c449de17a"),
"region" : "ppopopop",
"itinerary" : [
{
"_id" : ObjectId("5e1ca76b9f96d17c449de17d"),
"id" : 1,
"from" : "ppopopop",
"to" : "ashinnkn",
"mode" : "4444444444",
"day" : 2,
"duration_hrs" : 3
},
{
"_id" : ObjectId("5e1ca76b9f96d17c449de17c"),
"id" : 2,
"from" : "44444444444",
"to" : "Faketon2",
"mode" : "4444444444",
"day" : 2,
"duration_hrs" : 3
},
{
"_id" : ObjectId("5e1ca76b9f96d17c449de17b"),
"id" : 3,
"from" : "55555555555",
"to" : "ashin",
"mode" : "55555555",
"day" : 2,
"duration_hrs" : 3
}
],
"image_url" : "sadfasfsa",
},
{
"_id" : ObjectId("5e1ca76b9f96d17c449de178"),
"region" : "bktll",
"itinerary" : [
{
"_id" : ObjectId("5e1ca76b9f96d17c449de179"),
"id" : 1,
"from" : "mmkkkkm",
"to" : "ashin",
"mode" : "SkkkkA",
"day" : 2,
"duration_hrs" : 3
}
],
"image_url" : "sadfasfsa",
}
]
}
}
I want to update itinerary field inside packages which itself is an embedded document.
And my code is like this :
AgentPackage.update({
"_id" : mongoose.Types.ObjectId("5e1ca76b9f96d17c449de177"),
"packages.region" : "ppopopop",
'packages.itinerary.id': 2,
}, {$set: {'packages.itinerary.$$.from': "test" }}
I am not being able to update.I don't want to use indexing like 0,1 INSIDE query.
Try this :
If you've only one object inside packages with region : "ppopopop", then try this (this should suffice in most cases as you might not have duplicate regions with same name) :
AgentPackage.update({
_id: ObjectId("5e1ca76b9f96d17c449de177"), "packages.region": "ppopopop"
}, { $set: { "packages.$.itinerary.$[item].to": 'kausaltar' } }, {
arrayFilters: [{ 'item.id': 2 }]
})
If you've got multiple objects inside packages with region : "ppopopop", then try this :
AgentPackage.update({
_id: ObjectId("5e1ca76b9f96d17c449de177"), "packages.region": "ppopopop" // Here this "packages.region": "ppopopop" is optional as _id will only bring one document else might be helpful to bring only docs with region: ppopopop right after filter.
}, { $set: { "packages.$[eachPackage].itinerary.$[eachItinerary].to": 'kausaltar' } }, {
arrayFilters: [{ 'eachPackage.region': "ppopopop" }, { 'eachItinerary.id': 2 }]
})
Ref : update-positional-filtered
You can do it with $arrayfilter
db.getCollection("unit").update({_id: ObjectId("5e1ca76b9f96d17c449de177")}, { $set: { "packages.$[t].itinerary.$[d].from": "test" } },
{ arrayFilters: [ { "t.region": "ppopopop" }, {"d.id":15}]})

Mongo pull object from array inside array

i have inside my mongoDB collection this document
{
"_id" : ObjectId("5b633025579fac22e74bf3be"),
"FLAGS" : [
{
"toSent" : [
{
"_id" : ObjectId("5b633025579fac22e74bf3c2"),
"phone" : "+84404040404"
},
{
"_id" : ObjectId("5b633025579fac22e74bf3c1"),
"phone" : "+212652253403"
},
{
"_id" : ObjectId("5b633025579fac22e74bf3c0"),
"phone" : "+212123456788"
}
],
"_id" : ObjectId("5b633025579fac22e74bf3bf"),
"action" : "group_p_a"
},
{
"toSent" : [
{
"_id" : ObjectId("5b633031579fac22e74bf3c9"),
"phone" : "+212651077199"
},
{
"_id" : ObjectId("5b633031579fac22e74bf3c8"),
"phone" : "+84404040404"
},
{
"_id" : ObjectId("5b633031579fac22e74bf3c7"),
"phone" : "+212652253403"
},
{
"_id" : ObjectId("5b633031579fac22e74bf3c6"),
"phone" : "+212123456788"
}
],
"_id" : ObjectId("5b633031579fac22e74bf3c5"),
"action" : "group_p_a"
}
],
"time" : ISODate("2018-08-02T16:24:05.747+0000"),
"action_user_phone" : "+212123456788",
"idGroup" : "e534379a-1580-4568-b5ec-6eaf981538d2",
"nomGroup" : "MOH FOR EVER",
"__v" : NumberInt(0)
}
TODO
I need to remove for example this element { "_id" : ObjectId("5b633025579fac22e74bf3c2"), "phone" : "+84404040404"}
WHAT I DID
GroupEvents.update({}, {$pull:{FLAGS:{$elemMatch:{toSent:{phone: "+84404040404"} }}}},function(err,ret){
if(err)
console.log("error"+err);
if(ret)
console.log(ret);
});
It remove all what's inside toSent event if it doesn't match.
Any help please
You need to use $ positional operator instead of $elemMatch here
GroupEvents.update(
{ "Flags.toSent.phone": "+84404040404" },
{ "$pull": { "FLAGS.$.toSent": { "phone": "+84404040404" }}},
)
If you want remove from every element of FLAGS array this you need to use $[] the all positional operator
GroupEvents.update(
{ "Flags.toSent.phone": "+84404040404" },
{ "$pull": { "FLAGS.$[].toSent": { "phone": "+84404040404" }}},
)

Need to apply two group in sequence and second group should will have effect on result of first group

I want to group my data on the base of factoryId field and then each factory there will be multiple orders want to again group on basis of orderId as each order can contain multiple items. Here I am giving the example of my data and what I need and first group by which I tried.
{
"_id" : ObjectId("5b3e270c42d8004cea382e87"),
"factoryId" : ObjectId("5aa76190cef23a1561b8056c"),
"productId" : ObjectId("5aa78c66cef23a1561b80893"),
"orderId" : ObjectId("5b3e270c42d8004cea382e86"),
"generatedOrderId" : "3985-166770-4554",
"productName" : "Lakme Lotion"
},
{
"_id" : ObjectId("5b3e270c42d8004cea382e88"),
"factoryId" : ObjectId("5b39aed32832f72062e51c23"),
"productId" : ObjectId("5b3cb96139cec8341df52c4b"),
"orderId" : ObjectId("5b3e270c42d8004cea382e86"),
"generatedOrderId" : "3985-166770-4554",
"productName" : "Coke"
},
{
"_id" : ObjectId("5b3e27b07fe0d94d62b76b2a"),
"factoryId" : ObjectId("5aa76190cef23a1561b8057c"),
"productId" : ObjectId("5ac21075ac347a5fbf355028"),
"orderId" : ObjectId("5b3e27b07fe0d94d62b76b27"),
"generatedOrderId" : "3985-755507-7484",
"productName" : "Spoon"
}
And I want result as:
{
"factoryId":ObjectId("5aa76190cef23a1561b8057c"),
"orders":[
{
"orderId":ObjectId("5b3e270c42d8004cea382e86")
"items":[
{
"productName":"Lakme Lotion"
},
{
"productName":"Coke"
}
]
}
]
}
Can anyone help me with this?. Any help is appreciated.
I tried and It worked for me. Sorry
db.getCollection("transactions").aggregate(
[
{
"$group" : {
"_id" : "$orderId",
"items" : {
"$push" : "$$ROOT"
}
}
},
{
"$project" : {
"orderId" : "$_id",
"items" : "$items",
"_id" : 0
}
},
{
"$unwind" : {
"path" : "$items",
"preserveNullAndEmptyArrays" : false
}
},
{
"$group" : {
"_id" : "$items.factoryId",
"orders" : {
"$push" : "$$ROOT"
}
}
},
{
"$project" : {
"factoryId" : "$_id",
"orders" : "$orders",
"_id" : 0
}
}
]
);

Count where value does not match array

I have following offers collection
Here readBy contains the _id of the users...
Now I want to count the number of unRead offers for the userId = "5add82620d7f5b38240c63d4"
{
"_id" : ObjectId("5aeaab5ed6a9c97d0209260a"),
"expiresIn" : ISODate("2018-05-30T18:30:00.000Z"),
"name" : "Trip ",
"readBy" : [
ObjectId("5add82620d7f5b38240c63d4"),
ObjectId("5add82620d7f5b38240c63c6")
],
"__v" : 0
}
{
"_id" : ObjectId("5aeaab7dd6a9c97d0209260b"),
"expiresIn" : ISODate("2018-05-29T18:30:00.000Z"),
"name" : "Trip",
"readBy" : [ObjectId("5add82620d7f5b38240c63d4")],
"__v" : 0
}
{
"_id" : ObjectId("5aeae233d6a9c97d02092622"),
"expiresIn" : ISODate("2018-05-25T18:30:00.000Z"),
"name" : "two way off",
"readBy" : [],
}
{
"_id" : ObjectId("5aeae49643f10d284726069c"),
"expiresIn" : ISODate("2018-05-25T18:30:00.000Z"),
"name" : "two way off",
"readBy" : [],
}
{
"_id" : ObjectId("5aeae49743f10d284726069d"),
"expiresIn" : ISODate("2018-05-25T18:30:00.000Z"),
"name" : "two way off",
"readBy" : []
}
{
"_id" : ObjectId("5aeae49743f10d284726069e"),
"expiresIn" : ISODate("2018-05-25T18:30:00.000Z"),
"name" : "two way off",
"readBy" : []
}
so for the above collection my output should be
[{
numberOfUnreadOffers: 4
}]
because four of the collection does not have 5add82620d7f5b38240c63d4 in readBy array
You basically use $setIsSubset and $cond here:
var userId= "5add82620d7f5b38240c63d4";
Model.aggregate([
{ "$group": {
"_id": null,
"numberOfUnreadOffers": {
"$sum": {
"$cond": {
"if": {
"$setIsSubset": [[mongoose.Types.ObjectId(userId)], "$readBy"]
},
"then": 0,
"else": 1
}
}
}
}}
])
Of course you also need to "cast" using mongoose.Types.ObjectId from the "string" to a valid ObjectId value.
But really you get better performance from a simple count() instead:
Model.count({ "readBy": { "$ne": userId } })
So you really should not use .aggregate() for this at all.

Aggregate function in mongodb

I have a db Data as follows
{
"_id" : ObjectId("5a2109572222085be93ef10d"),
"name" : "data1",
"date" : "2017-12-01T00:00.0Z",
"status" : "COMPLETED"},{
"_id" : ObjectId("5a2109572222085be93ef10d"),
"name" : "data1",
"date" : "2017-12-01T00:00.0Z",
"status" : "FAILED"}
and I want an aggreagate output as follows
{ date:"2017-12-01T00:00:0Z", total:"2", completed:1, failed:1 }
I have tried this code but didn't produce the result as above
db.test.aggregate([
{$group: {_id : {date : '$date',status:'$status'}, total:{$sum :1}}},
{$project : {date : '$_id.date', status : '$_id.status', total : '$total', _id : 0}}
])
db.test.aggregate(
// Pipeline
[
// Stage 1
{
$group: {
_id:"$date",
total:{$sum:1},
failed:{$sum:{$cond:[{$eq:["$status","FAILED"]},1,0]}},
completed:{$sum:{$cond:[{$eq:["$status","COMPLETED"]},1,0]}}
}
},
// Stage 2
{
$project: {
date : '$_id',
total : 1,
failed : 1,
completed : 1,
_id : 0,
}
},
]
);

Resources