Remove of $unwind operation from array in mongodb - node.js

There are multiple collections one of these are.
users
place
The document stored in the database which is given below.
{
"_id" : "1eca51f0-538d-11e8-89fc-d125355b590d",
"organization" : [
{
"associationIds" : {
"dObjectIds" : [
{
"dObjectData" : {
"objectId" : "fd047ddf-61c2-4df2-8241-62af0399c8c1",
"objectName" : "shift",
"dObjectId" : "49492544-e4e3-491b-b967-a6f62330da3f"
}
}
]
},
"organizationId" : "1c3f6150-538d-11e8-89fc-d125355b590d",
"privelege" : "Admin",
"organizationName" : "ABC"
},
{
"associationIds" : {
"dObjectIds" : [
{
"dObjectData" : {
"objectId" : "ad047ddf-61c2-4df2-8241-62af0399c5c1",
"objectName" : "shift",
"dObjectId" : "38492544-e4e3-491b-b967-a6f62330da3f"
}
},
{
"dObjectData" : {
"objectId" : "fd047ddf-61c2-4df2-8241-62af0399c8c2",
"objectName" : "department",
"dObjectId" : "49492544-e4e3-491b-b967-a6f62330da1f"
}
}
]
},
"organizationId" : "1c3f6150-538d-11e8-89fc-d125355b591d",
"privelege" : "Manager",
"organizationName" : "XYZ"
}
]}
I'm using these query.
db.users.aggregate([
{$match: {'_id': '1eca51f0-538d-11e8-89fc-d125355b590d'}},
{$unwind :'$organization'},
{$match:{'organization.organizationId':'1c3f6150-538d-11e8-89fc-d125355b591d'}},
{$unwind:'$organization.associationIds.dObjectIds'},
{'$lookup': {
'from': 'places',
localField:'organization.associationIds.dObjectIds.dObjectData.dObjectId',
foreignField: 'dObjectData.dObjectId',
as: 'associationData'
}
},
{'$project': {
'associationData': 1
}
}
])
I have used $unwind two times in a query which has more expensive.Is there any way or operation which can we use instead of multiple times of $unwind.
NOTE: I waana result like this(result of associationData which get the velue from other collection so I used $lookup)
{
_id" : "c6114ee0-c82f-11e6-9b1e-6140212f8693",
"associationData" : [
{
"_id" : "f09f5d70-ad7e-11e7-87bd-cd873956707e",
"dObjectData" : {
"departmentName" : "CEO & Directors",
"dObjectId" : "ab034106-ad7d-11e7-abc4-cec278b6b50a",
"objectName" : "Departments",
"objectId" : "63735ee2-ad79-11e7-abc4-cec278b6b50a",
"updatedOn" : ISODate("2017-10-10T11:20:37.255+05:30"),
"addedOn" : ISODate("2017-10-10T11:20:37.255+05:30")
},
"associationIds" : {
"organizationId" : "af39bc69-1938-4149-b9f7-f101fd9baf73",
"placeIds" : [ ],
"assignmentIds" : [ ],
"beaconIds" : [ ],
"userIds" : [ ]
}
}]}
I'll be very thankful.

Related

Mongo update to many query

does anyone know how to change a propertie value in mongo
from
i changed JSON.units[0].services[0].label from etiket controle to AuditLabel
i tried this:
db.getCollection('assortiment').updateMany({"units.$[].services.$[].label": "etiket controle"},{ "$set": { "units.$[].services.$[].label": "AuditLabel" }})
but no succes because it dont select anything
{
"_id" : "764",
"meta" : {
"groupsId" : "764",
"type" : "DRYGR"
},
"units" : [
{
"unit" : "BASE_UNIT_OR_EACH",
"gtin" : "08711728556206",
"services" : [
{
"label" : "etiket controle",
"collection" : "gtins"
}
]
}
]
}
to
{
"_id" : "764",
"meta" : {
"groupsId" : "764",
"type" : "DRYGR"
},
"units" : [
{
"unit" : "BASE_UNIT_OR_EACH",
"gtin" : "08711728556206",
"services" : [
{
"label" : "AuditLabel",
"collection" : "gtins"
}
]
}
]
}
Try this code its work's for me
db.getCollection('assortiment').updateMany(
{
"units.services.label": "etiket controle"
},
{
"$set":
{ "units.$[].services.$[].label": "AuditLabel" }
}
)

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" }}},
)

How to use aggregation correctly in MongoDB with embbeded documents?

I have a collection with folowing data:
{
"_id" : ObjectId("5b5066b716d3112cfc2a5deb"),
"username" : "admin",
"password" : "123456",
"token" : "0123",
"bots" : [
{
"name" : "mybot",
"installations" : [
{
"date" : ISODate("2018-07-19T10:23:51.774Z")
},
{
"date" : ISODate("2018-07-19T10:23:51.774Z")
}
],
"commands" : [
{
"name" : "read",
"date" : ISODate("2018-07-19T10:23:51.774Z")
},
{
"name" : "answer",
"date" : ISODate("2018-07-19T10:23:51.774Z")
},
{
"name" : "get",
"date" : ISODate("2018-07-19T11:55:28.858Z")
},
{
"name" : "get",
"date" : ISODate("2018-07-19T11:56:47.419Z")
},
{
"name" : "get",
"date" : ISODate("2018-07-19T11:56:48.499Z")
},
{
"name" : "get",
"date" : ISODate("2018-07-19T11:56:49.089Z")
}
]
}
]
},
{
"_id" : ObjectId("5b50bbfe3ed35b6f2bde6923"),
"username" : "user",
"password" : "123456",
"token" : "44444",
"bots" : [
{
"name" : "anotherBotName",
"installations" : [
{
"date" : ISODate("2018-07-19T16:27:42.012Z")
},
{
"date" : ISODate("2018-07-19T16:27:42.012Z")
}
],
"commands" : [
{
"name" : "update",
"date" : ISODate("2018-07-19T16:27:42.012Z")
},
{
"name" : "update",
"date" : ISODate("2018-07-19T16:27:42.012Z")
}
]
}
]
}
I want to execute SQL-equivalent query
SELECT commands.name, COUNT(commands.name), GROUP BY commands.name
and get a result like:
[
{update: 2},
{get: 4},
{read: 1},
{answer: 1}
]
but when I execute this query in mongo:
.collection(collectionName).aggregate({{'$group': {_id: "$bots.commands.name",count:{$sum:1}}}
}).toArray(callback)
I get such a result:
[
{
_id: [
[ 'test', 'test1' ]
],
count: 1
},
{
_id: [
[ 'read', 'answer', 'get', 'get', 'get', 'get' ]
],
count: 1
}
]
I googled and read about agregation in MongoDB and still don't get much. It's hard to move from SQL to NoN-SQL database
My questions are:
Why my query shows not the result I want to see?
How to fix it?
Thanks in advance!
Since you have two nested arrays in your schema you should use $unwind operator twice before you apply your $group. After $unwind you'll get separate document for each name. Try:
db.col.aggregate([
{
$unwind: "$bots"
},
{
$unwind: "$bots.commands"
},
{
$group: {
_id: "$bots.commands.name",
count: { $sum: 1 }
}
},
{
$replaceRoot: {
newRoot: {
$let: {
vars: { obj: [ { k: "$_id", v: "$count" } ] },
in: { $arrayToObject: "$$obj" }
}
}
}
}
])
In the last stage you can use $replaceRoot with $arrayToObject to set _id as keys in your final objects.
Outputs:
{ "update" : 2 }
{ "get" : 4 }
{ "answer" : 1 }
{ "read" : 1 }

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
}
}
]
);

How can I check if my aggregate query is good or bad?

How can I check if my aggregate query is good or bad? I already use "explain" but it's not specific.
Here's the output of my aggregate "explain".
{
"waitedMS" : NumberLong(0),
"stages" : [
{
"$cursor" : {
"query" : {
"keys.license_id" : ObjectId("580eeb7fb79bec95648775a2"),
"deleted.status" : {
"$ne" : 1
}
},
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "serpentsmsapp.conversations",
"indexFilterSet" : false,
"parsedQuery" : {
"$and" : [
{
"keys.license_id" : {
"$eq" : ObjectId("580eeb7fb79bec95648775a2")
}
},
{
"$not" : {
"deleted.status" : {
"$eq" : 1
}
}
}
]
},
"winningPlan" : {
"stage" : "COLLSCAN",
"filter" : {
"$and" : [
{
"keys.license_id" : {
"$eq" : ObjectId("580eeb7fb79bec95648775a2")
}
},
{
"$not" : {
"deleted.status" : {
"$eq" : 1
}
}
}
]
},
"direction" : "forward"
},
"rejectedPlans" : [ ]
}
}
},
{
"$sort" : {
"sortKey" : {
"_id" : 1,
"keys.license_id" : 1,
"status.deleted" : 1
}
}
},
{
"$lookup" : {
"from" : "conversation_messages",
"as" : "cmf",
"localField" : "_id",
"foreignField" : "keys.conv_id",
"unwinding" : {
"preserveNullAndEmptyArrays" : false
}
}
},
{
"$match" : {
"cmf.deleted.status" : 0
}
},
{
"$sort" : {
"sortKey" : {
"cmf.deleted.status" : -1
}
}
},
{
"$group" : {
"_id" : {
"id" : "$_id",
"number" : "$number",
"mode" : "$mode",
"keys" : "$keys",
"ports" : "$ports",
"user_assign" : "$user_assign",
"spam" : "$spam"
},
"cm_field" : {
"$last" : {
"id" : "$cmf._id",
"message" : "$cmf.message",
"ports" : "$cmf.ports",
"mode" : "$cmf.mode",
"keys" : "$cmf.keys",
"status" : "$cmf.status",
"date" : "$cmf.updated"
}
},
"counts" : {
"$sum" : "$cmf.status"
},
"sms_mode" : {
"$addToSet" : "$cmf.mode"
}
}
},
{
"$sort" : {
"sortKey" : {
"cm_field.date" : -1
},
"limit" : NumberLong(5000)
}
},
{
"$group" : {
"_id" : "$_id",
"cm_field" : {
"$last" : "$cm_field"
},
"counts" : {
"$first" : "$counts"
},
"sms_mode" : {
"$first" : "$sms_mode"
}
}
}
],
"ok" : 1
}
How can I see how many docs are scanned before performing my query?
In order to solve your problem I suggest you the following plan
Learn how does Explain work.
"Good or bad" approach is not an engineering approach, it always depends on a lot of factors (requirements, hardware, etc...). You should define what are those requirements before answering if it query is performant enough.
For your specific explain log. "COLSCAN" - means it has used all your documents on the collection to aggregate the result, this usually is an alert sign, you should think of using proper indexes.

Resources