Count Number of objects present on an array under Specific MongoDB ID - mongodb

My MongoDB Data Structure is like this
{
"_id" : ObjectId("5a3a67b102d9d926f8cd66b8"),
"createdate" : ISODate("2017-12-20T13:37:53.921Z"),
"groupmember" : [
{
"membername" : "a",
"memberid" : "5a20ee1acdacc7086ce7742c"
},
{
"membername" : "b",
"memberid" : "5a20eb5bcdacc7086ce77427"
},
{
"membername" : "c",
"memberid" : "5a20ee35cdacc7086ce7742d"
},
{
"membername" : "d",
"memberid" : "5a20ee67cdacc7086ce7742e"
},
{
"membername" : "e",
"memberid" : "5a20ee9acdacc7086ce7742f"
}
],
"__v" : 0
}
Now I want to calculate the total Number of member present on Group member Array.
I have a solution but it will not for Any specific id.
What I have Solution is like this
Test.aggregate([
{$group:{'_id': '$_id', 'total': { $sum: { $size:"$groupmember" } }}}
], function(error, data){
if (error) {
console.log(error)
} else {
console.log(data);
}
});
So this approach returns all count of the database.
I also tried Match and unwind But it returns blank array. like this
Test.aggregate([
{$match: {_id: '5a3a67b102d9d926f8cd66b8'}},
{$unwind: "$groupmember"},
{$group:{'_id': '$_id', 'total': { $sum: { $size:"$groupmember" } }}}
], function(error, data){
if (error) {
console.log(error)
} else {
console.log(data);
}
});

You can do like:
Test.aggregate(
[
{
$project: {
noOfGroupMembers: { $size: "$groupmember" }
}
}
]
)
If you want to do it with id:
Test.aggregate(
[
{
$match:"5a3a67b102d9d926f8cd66b8"
},
{
$project: {
noOfGroupMembers: { $size: "$groupmember" }
}
}
]
)

Test.find({_id: '5a3a67b102d9d926f8cd66b8'}, function(err, data){
if(err){
console.log(err)
} else {
var length = data[0].groupmember.length;
console.log(length);
}
});

Related

How to use the key of mongoDB collection as a key with some value in my query result?

Suppose this is my collection :
{
{
"productType":"bike",
"productID":1,
"lat":22.7,
"long":77.4
},
{
"productType":"car",
"productID":5,
"lat":25.7,
"long":75.4
},
{
"productType":"bike",
"productID":2,
"lat":26.7,
"long":76.4
}
}
I want to use the product type as key to my mongo query and grouping to get result like this :
{
"bike":{
"1":{
"latitude":"22.7",
"longitude":"77.4"
},
"2":{
"latitude":"26.7",
"longitude":"76.4"
}
},
"car":{
"5":{
"latitude":"25.7",
"longitude":"75.4"
}
}
}
I tried to use $replaceRoot but could not get the desired result.
Try this query:
db.products.aggregate([
{
$group: {
_id: "$productType",
products: {
$push: {
"k": { $toString: "$productID" },
"v": {
latitude: "$lat",
longitude: "$long"
}
}
}
}
},
{
$replaceWith: {
array: [
{
k: "$_id",
v: { $arrayToObject: "$products" }
}
]
}
},
{
$replaceRoot: {
newRoot: { $arrayToObject: "$array" }
}
}
]);
Output:
/* 1 */
{
"bike" : {
"1" : {
"latitude" : 22.7,
"longitude" : 77.4
},
"2" : {
"latitude" : 26.7,
"longitude" : 76.4
}
}
},
/* 2 */
{
"car" : {
"5" : {
"latitude" : 25.7,
"longitude" : 75.4
}
}
}

How to combine results in a Mongo aggregation query

I'm new to aggregation queries in Mongo and been really struggling trying to produce the output I want. I have the following aggregation query:
db.events.aggregate([
{ $match: { requestState: "APPROVED" } },
{ $unwind: { path: "$payload.description" } },
{ $group: { _id: { instr: "$payload.description", bu: "$createdByUser", count: { $sum: 1 } } } }
]);
that returns the following results:
{ "_id" : { "instr" : "ABC-123", "bu" : "BU2", "count" : 1 } }
{ "_id" : { "instr" : "ABC-123", "bu" : "BU1", "count" : 1 } }
{ "_id" : { "instr" : "DEF-456", "bu" : "BU1", "count" : 1 } }
How can I amend the aggregation query so that there are only 2 documents returned instead of 3? With the two "ABC-123" results combined into a single result with a new array of counts with the "bu" and "count" fields i.e.
{ "_id" : { "instr" : "ABC-123", "counts": [ { "bu" : "BU1", "count" : 1 }, { "bu" : "BU2", "count" : 1 } ] } }
Many thanks
You can add another stage to only $group by _id.instr and another stage to $project to your desired output shape
db.events.aggregate([
{
$match: { requestState: "APPROVED" }
},
{
$unwind: { path: "$payload.description" }
},
{
$group: {
_id: { instr: "$payload.description", bu: "$createdByUser", count: { $sum: 1 } }
}
},
{
$group: {
_id: { instr: "$_id.instr" },
counts: { $push: { bu: "$_id.bu", count: "$_id.count" } }
}
},
{
$project: {
_id: { instr: "$_id.instr", counts: "$counts" }
}
}
]);

Remove aggregate with conditions

I have the a collection of documents as follows an example document:
{
'publicacao' : { 'data': '2013-13-13', 'hora': '13:13:13'},
'conteudo' : 'https://docs.google.com/document/d/1EQynJTiBa6FNI2O8XfoV0clMPxS5uOAu0_jKyEwsTBE/edit?usp=sharing',
'titulo' : 'As histórias de ciclano',
'categoria' : 'Romance',
'autor' : 'Ciclano',
'avaliacoes': [
{
'leitor': 'Fulano',
'nota': 1
},
{
'leitor': 'Beltrano',
'nota': 0
}
],
'denuncias': [
{
'denunciante': 'Ciclano'
},
{
'denunciante': 'Beltrano'
}
]
}
then i made an aggregate to define some documents to be removed:
var cursor = db.livro.aggregate( [
{
$project: {
id:1,
remover: {
$gt: [
{ $size: "$denuncias" },
{
$divide: [
{ $size: "$avaliacoes" },
2
]
}
]
}
}
}
]);
this aggregation returns the following docs:
{ "_id" : ObjectId("5cf5a9be7d48c53504974439"), "remover" : false }
{ "_id" : ObjectId("5cf5a9be7d48c5350497443a"), "remover" : false }
{ "_id" : ObjectId("5cf5a9be7d48c5350497443b"), "remover" : true }
{ "_id" : ObjectId("5cfd746e40d53565ca52132b"), "remover" : false }
{ "_id" : ObjectId("5cfd746e40d53565ca52132c"), "remover" : false }
{ "_id" : ObjectId("5cfd746e40d53565ca52132d"), "remover" : true }
I need to remove all docs with "remove": true.
I don't know how to get those ones!
Resolved:
I used the cursor.forEach() to iterate the objects and find the objects with remove = true.
cursor.forEach(function (doc){
if(doc.remover == true) {
db.livro.remove({"_id": doc._id});
print("Doc removido: "+ doc._id)
}
});
Instead of doing this with code after the query it is better overall to do it in the actual aggregation. Just check with a $match if the array has an element:
db.collection.aggregate([
{
$match: {
"denuncias.0": {
$exists: true
}
}
},
{
$project: {
id: 1,
remover: {
$gt: [
{
$size: "$denuncias"
},
{
$divide: [
{
$size: "$avaliacoes"
},
2
]
}
]
}
}
}
])
You can see if working here

How to access the second level array in mongodb (with group)

here is sample collection:
{
"_id":ObjectId("5cc7d8e88c33e065c56b0883"),
"age":70,
"child":[
{
"id":"son1",
"age":40,
"grandSon":[
{
"id":"grand1",
"age":10,
"like":[
{
"id":"like1",
"info":"apple"
},
{
"id":"like2",
"info":"banana"
}
],
"grandGrandSon" :[
{
"id":"grandGrand1",
"age":10
},
{
"id":"grandGrand2",
"age":13
}
]
},
{
"id":"grand2",
"age":13,
"like":[
{
"id":"like1",
"info":"apple"
}
],
"grandGrandSon" :[
{
"id":"grandGrand1",
"age":12
},
{
"id":"grandGrand2",
"age":14
}
]
}
]
},
{
"id":"son2",
"age":40,
"grandSon":[
{
"id":"grand1",
"age":10,
"like":[
{
"id":"like1",
"info":"apple"
},
{
"id":"like2",
"info":"banana"
}
],
"grandGrandSon" :[
{
"id":"grandGrand1",
"age":15
},
{
"id":"grandGrand2",
"age":16
}
]
},
{
"id":"grand2",
"age":14,
"like":[
{
"id":"like1",
"info":"apple"
},
{
"id":"like2",
"info":"banana"
}
],
"grandGrandSon" :[
{
"id":"grandGrand1",
"age":12
},
{
"id":"grandGrand2",
"age":13
}
]
}
}
]
}
]
I want to result like this
parent age and child'size and like grandSons Count, grandGrandSons count and child's like count
{
"_id": ObjectId("5cc7d8e88c33e065c56b0883"),
"age": 70,
"childCount": 2,
"grandSonsCount": 4
"likeCount": 7
"grandGrandSonsCount": 8,
"grandSonsAgeCount": 105
}
here is my code
{
$lookup:
{
from: "..."
localField: "...",
foreignField: "..",
as: "child"
},
},
{ $unwind: "$child" }
{ $group : {
_id : "$_id",
age: {$first:"$age"},
childCount: {$sum: 1},
grandSonsCount : {$sum : {$size : "$child.grandSon"}},
likeCount: {$sum : {$size : "$child.like"}},
grandGrandSonsCount :
{$sum : {$sum : {$size : "$child.grandSon.grandGrandSon"}}},
//it is return 4(grandSonsCount)
}},
I used lookup, making for above collection(child)
it return grandSon count, but I want to get grandGrandSon Count
how can I get nested array in nested array of size?
how can I have to do??
Add $reduce to the group stage:
{
"$group" : {
....
....
"grandGrandSonsCount" : {
"$sum" : {
"$reduce" : {
"input" : "$child.grandSon",
"initialValue" : 0,
"in" : {
"$sum" : [
"$$value",
{
"$size" : "$$this.grandGrandSon"
}
]
}
}
}
}
}
}

Where and Group By Using Moongose API MongoDB

I have written an aggregation function which will count the Message. Based on Message Status.
exports.countRecords = function(req, res) {
Message.aggregate([{
$group: {
_id: "$message_status",
count: {
$sum: 1
}
}
}, {
$sort: {
_id: 1
}
}], function(err, result) {
if (err) {
console.log(err);
return;
}
console.log(result);
res.jsonp(result);
});
};
Now i need to add a condition to count only when the channel_message_ID and channel_thread_Id are equal so i have modified the logic like below:
Message.aggregate([{
$match: {
channel_message_ID: { $eq: ["$channel_message_ID", "$channel_thread_Id"]}
}},
{$group: {
_id: "$message_status",
count: {
$sum: 1
}
},
}, {
$sort: {
_id: 1
}
}], function(err, result) {
if (err) {
console.log(err);
return;
}
console.log(result);
res.jsonp(result);
});
};
It is not at all working. Thanks in Advance.
try below solution:
$project:
Message.aggregate([{
{"$project": {
"channel_message_ID":1,
"channel_thread_Id":1,
"message_status": 1,
"cond": {"$eq":["$channel_message_ID","$channel_thread_Id"]}
}
},
{"$match":{"cond": true}},
{$group: {
_id: "$message_status",
count: {
$sum: 1
}
},
}, {
$sort: {
_id: 1
}
}], function(err, result) {
if (err) {
console.log(err);
return;
}
console.log(result);
res.jsonp(result);
});
You'll need to add a new field to the document at the first stage of the aggregation pipeline, this can be done by using the [$addFields]
(https://docs.mongodb.com/manual/reference/operator/aggregation/addFields/) stage
{ "$addFields" : { "idMatch" : { "$eq" : [ "$channel_message_ID" , "$channel_thread_Id" ] } } }
This will create us a new field on the documents flowing through the pipeline telling us if there is a match on the 2 fields. We can then push this in to a $match stage
{ $match: { "idMatch" : true } }
Then you can run the rest of the $group:
{ "$group" : { "_id" : "$message_status", "count" : { "$sum" : 1 } } }
then sort stage:
{ "$sort" : { "_id" : 1 } }
So for example if we add the following documents to a mongodb collection:
db.test.insertMany([{
message_status: "In Progress",
channel_thread_Id: "A",
channel_message_ID: "A"
},
{
message_status: "Completed",
channel_thread_Id: "A",
channel_message_ID: "A"
},
{
message_status: "In Progress",
channel_thread_Id: "A",
channel_message_ID: "B"
},
{
message_status: "Completed",
channel_thread_Id: "A",
channel_message_ID: "B"
}]);
{
"acknowledged" : true,
"insertedIds" : [
ObjectId("599abef4f0cd60f52d67215a"),
ObjectId("599abef4f0cd60f52d67215b"),
ObjectId("599abef4f0cd60f52d67215c"),
ObjectId("599abef4f0cd60f52d67215d")
]
}
We can then run the following aggregation query:
db.test.aggregate([
{ "$addFields" : { "idMatch" : { "$eq" : [ "$channel_message_ID" , "$channel_thread_Id" ] } } },
{ $match: { "idMatch" : true } },
{ "$group" : { "_id" : "$message_status", "count" : { "$sum" : 1 } } },
{ "$sort" : { "_id" : 1 } }
]);
Which will return the expected results of
{ "_id" : "Completed", "count" : 1 }
{ "_id" : "In Progress", "count" : 1 }