How to get count of elements in document array - MongoDB? - javascript

I have the following MongoDB collection (JSON):
{
"_id" : ObjectId("570185458351bbac27bc9a20"),
"email" : "test#gmail.com",
"applicants" : [
{
"id" : "570724e4ae4f8a5026156999",
"email" : "a#gmail.com",
},
{
"id" : "570724e4ae4f8a5026156333",
"email" : "a2#gmail.com",
},
{
"id" : "570724e4ae4f8a5026156111",
"email" : "a3#gmail.com",
},
{
"id" : "570724e4ae4f8a5026156222",
"email" : "a4#gmail.com",
}
],
},
{
"_id" : ObjectId("570185458351bbac27bc9a20"),
"email" : "test#gmail.com",
"applicants" : [
{
"id" : "570724e4ae4f8a5026156555",
"email" : "a#gmail.com",
},
{
"id" : "570724e4ae4f8a5026156666",
"email" : "a2#gmail.com",
},
],
},
{
"_id" : ObjectId("570185458351bbac27bc9a20"),
"email" : "test2#gmail.com",
"applicants" : [
{
"id" : "570724e4ae4f8a5026156555",
"email" : "a#gmail.com",
},
{
"id" : "570724e4ae4f8a5026156666",
"email" : "a2#gmail.com",
},
],
}
I would like to get the count of the elements in all arrays of the of the document where the email = test#gmail.com. How can I go about getting that count?
I am using the following to get the number of documents with email test#gmail.com using this:
collection.count({"email" : tmpEmail}, function (err, count) {
res.json(count);
console.log("Number: " + count);
});
How can I go ahead and count the number of elements in all applicant arrays for the documents where the email is test#gmail.com? The could for the example above would be: 6.
EDIT:
As per one of the answers I modified my query to the following:
Answer 1:
collection.aggregate(
{$match: {"email": req.user.username, "status" : "true"}},
{$unwind: "$applicants"},
{$group: {_id:null, count: {$sum :1}}, function (err, count) {
res.json(count);
console.log("Number of New Applicants: " + count);
}
});
Answer 2:
collection.aggregate(
[{$match:{"email" : req.user.username, "status" : "true"}},
{$project:{_id:0, email:1, totalApplicants:{$size:"$applicants"}}},
{$group:{_id:"$employer", count:{$sum:"$totalApplicants"}}}],
function (err, count){
res.json(count);
console.log("Number of New Applicants: " + count);
});

You can use an aggregate query instead:
collection.aggregate(
[{$match: {"email": req.user.username, "status" : "true"}},
{$unwind: "$applicants"},
{$group: {_id:null, count: {$sum :1}}}], function (err, result) {
console.log(result);
console.log("Number of New Applicants: " + result[0].count);
if(result.length > 0)
res.json(result[0]);
else
res.json({count:0});
}
});
This will result you in one document where count will have your required result

This may require to write a aggregation since you need to count the size of applicants array grouped by email:
Here is the equivalent mongodb query that returns the expected email with count:
db.yourCollection.aggregate(
[{$match:{"email" : "test#gmail.com"}},
{$project:{_id:0, email:1,totalEmails:{$size:"$applicants"}}},
{$group:{_id:"$email", count:{$sum:"$totalEmails"}}}])
This returns { "_id" : "test#gmail.com", "count" : 6 }
You may need to change this according to your code.

Related

How to get all fields of a MongoDB document

In application I write down in a collection of users documents with separate users. Each document is an object in which there is a name of the user and his category. Categories are an object. How can I take all recorded categories. I try to take them through find (), but there I need to specify the key-value. And I just need to specify the category field and take all the key-values ​​there. How can I get all categories of an individual user?
I need to find them by key.
mongoClient.connect(function (err, client) {
const db = client.db("expensesdb");
const collection = db.collection("users");
if (err) return console.log(err);
collection
.find({ name: "Bob"})
.toArray(function (err, results) {
console.log(results);
client.close();
});
});
Sample data-set
{ "_id" : ObjectId("63050125848392dcf6f3ebba"), "name" : "max", "category" : { "cat1" : "max1", "cat2" : "max2" } }
{ "_id" : ObjectId("63050132848392dcf6f3ebbb"), "name" : "box", "category" : { "cat1" : "box1", "cat2" : "box2" } }
Try this aggregation pipeline :
db.users.aggregate([
{ $match: { "name": "max" } },{$project : {"category":1}}
]);
db.users.aggregate([
{ $match: { "category.cat1": "cat1" } },{$project : {"category":1}}
]);
Output for both:
{ "_id" : ObjectId("630500ec848392dcf6f3ebb9"), "category" : { "cat1" : "cat1", "cat2" : "cat2" } }

Mongoose aggregate query working as a mongodb query but not able to convert to mongoose

Below is my JSON structure
[{
"_id" : ObjectId("626204345ae3d8ec53ef41ee"),
"categoryName" : "Test Cate",
"__v" : 0,
"createdAt" : ISODate("2022-04-22T01:26:11.627Z"),
"items" : [
{
"itemName" : "Cate",
"user" : ObjectId("6260729af547915d9d876c23"),
"itemDescription" : "slkkndanslk",
"itemImage" : "/images/camping-table.jpeg",
"_id" : ObjectId("626204339b24b2ead6c05a70"),
"updatedAt" : ISODate("2022-04-22T01:26:11.627Z"),
"createdAt" : ISODate("2022-04-22T01:26:11.627Z")
}
],
"updatedAt" : ISODate("2022-04-22T01:26:11.627Z")
},
{
"_id" : ObjectId("62620e725ae3d8ec53ef4aa8"),
"categoryName" : "sdsad",
"__v" : 0,
"createdAt" : ISODate("2022-04-22T02:09:54.028Z"),
"items" : [
{
"itemName" : "asdada",
"user" : ObjectId("62620e6299145edb95147482"),
"itemDescription" : "asdsadad",
"itemImage" : "/images/camping-table.jpeg",
"_id" : ObjectId("62620e7299145edb95147486"),
"updatedAt" : ISODate("2022-04-22T02:09:54.028Z"),
"createdAt" : ISODate("2022-04-22T02:09:54.028Z")
},
{
"itemName" : "dsdsa",
"user" : ObjectId("62620e6299145edb95147482"),
"itemDescription" : "adasdad",
"itemImage" : "/images/camping-table.jpeg",
"_id" : ObjectId("62621b9c3662e0b4acabb71f"),
"updatedAt" : ISODate("2022-04-22T03:06:04.727Z"),
"createdAt" : ISODate("2022-04-22T03:06:04.727Z")
}
],
"updatedAt" : ISODate("2022-04-22T03:06:04.727Z")
}]
This is just one document and there would be array of documents. Also there may be multiple items within the same category.
I want to fetch all the items in all category with a particular userid. In MongoDB below is my query which is giving correct output on mongo shell
db.trades.aggregate([
{
$unwind: "$items"
},
{
$match: {
"items.user": ObjectId("6260729af547915d9d876c23")
}
}
]).pretty()
In mongoose I am doing the following thing but not getting the result
tradeModel.aggregate([ { $unwind : "$items" }, { $match : { "items.user" : id } } ])
.then(res => {
console.log(JSON.stringify(res))
})
Let me know what I am missing
Your parameter id is type string but mongodb store type ObjectId
change
tradeModel.aggregate([ { $unwind : "$items" }, { $match : { "items.user" : id } } ])
.then(res => {
console.log(JSON.stringify(res))
})
into
tradeModel.aggregate([ { $unwind : "$items" }, { $match : { "items.user" : {"$oid": id} } } ])
.then(res => {
console.log(JSON.stringify(res))
})
Got the answer we can use ObjectId(id) in search like this
tradeModel.aggregate([ { $unwind : "$items" }, { $match : { "items.user" : ObjectId(id) } } ])
.then(res => {
console.log(JSON.stringify(res))
})

Mongoose (MongoDB) - Error: Can't use $each with Number

I've to push a given array of Number values into a selected Document inside my MongoDB database.
The Document that I'm going to update as the following structure:
{
"_id" : {
"id" : 17,
"type" : "f"
},
"__v" : 0,
"created_at" : ISODate("2017-03-22T11:16:21.403Z"),
"token" : {
"expDate" : ISODate("2017-12-31T00:00:00Z"),
"token" : "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJlbWFpbCI6ImFsYWRpbkBjb25zb3J6aW9jZXIuaXQiLCJleHAiOjE1MTQ2Nzg0MDB9.QvbT146bA_KH5XA7MH8ASXm9cr3sPZChJ3prYyDireI"
},
"updated_at" : ISODate("2017-07-24T09:42:33.741Z"),
"plots" : {
"idPlot" : [
23570,
23475
]
},
"machines" : [
{
"idPlotBind" : 1,
"ip" : "",
"mac" : "18-5F-00-4A-FE-F4",
"irrId" : 31,
"_id" : ObjectId("59084f527d634d301338aac6"),
"addr" : "pialadin.ddns.net"
},
{
"idPlotBind" : null,
"ip" : "",
"mac" : "12-01-02-FE-AB-B2",
"irrId" : 35,
"_id" : ObjectId("59084f7d7d634d301338aac7")
}
]
}
I'm using the Mongoose library for JS, and the accused query is this one:
userSchema.findOneAndUpdate({$and:[{ '_id.id': resData.PlotRows.IdUser}, {'_id.type': 'f'}]},{$addToSet:{'plots.$.idPlot': {$each: plotData}}}, {upsert: false}, function(err, usr){
if(err){
console.log(err);
return;
}
});
But when I try to execute it, gives me back:
Error: Can't use $each with Number

How to update record in MongoDB without replacing the existing fields?

When I am update a record, it removes the existing fields and adds the new ones.
This was the record before the update:
{ "_id" : ObjectId("56a356863aa433ae37dc2cee"), "browser" : "Chrome", "version" : 47}
This was the command I executed:
db.collection('profiles')
.update({
'_id' : obj("56a356863aa433ae37dc2cee") },
{"first_name" : first_name, "last_name" : last_name, "email" : email},
function (err, result) {
console.log(result);
});
This was the record after I had executed the update command:
{ "_id" : ObjectId("56a356c9a08487ed3719e40a"), "first_name" : "kaushik", "last_name" : "makwana", "email" : "kdmakwana" }
Same as the updating existing collection field, $set will add a new fields if the specified field does not exist.
> db.foo.find()
> db.foo.insert({"test":"a"})
> db.foo.find()
{ "_id" : ObjectId("4e93037bbf6f1dd3a0a9541a"), "test" : "a" }
> item = db.foo.findOne()
{ "_id" : ObjectId("4e93037bbf6f1dd3a0a9541a"), "test" : "a" }
> db.foo.update({"_id" :ObjectId("4e93037bbf6f1dd3a0a9541a") },{$set : {"new_field":1}})
> db.foo.find()
{ "_id" : ObjectId("4e93037bbf6f1dd3a0a9541a"), "new_field" : 1, "test" : "a" }
use $set to update fields or add new fields. Your query should be:
db.collection('profiles').update(
{
'_id' : obj("56a356863aa433ae37dc2cee")
},
{ $set:{{"first_name" : first_name, "last_name" : last_name, "email" : email}} },
function (err, result){
console.log(result);
});

MongoDB: Adding an array into an existing array

I'm trying to add an "Instructors" array into an already existing "Camps" array.
The hierarchical structure looks something like this:
owner = {
email : 'john.smith#gmail.com',
password : 'mypassword',
firstName : 'john',
lastName : 'smith',
camps : [
{
name : 'cubs-killeen',
location : 'killeen',
manager : {name: 'joe black', email: '', password: ''},
instructors : [
{
firstName : 'bill',
lastName : 'jones',
classes : []
},
{
firstName : 'jill',
lastName : 'jones',
classes : [],
},
],
students : []
}
]
};
I am using Node Express with MongoJS and have been able to successfully add an owner and add "camps", however, in the "addInstructor" function, when I try and add "Instructors" to a particular camp that is when the problems occur. I get no error message, instead it simply appends the "Instructors" array AFTER the items in the camps array.
Any help would be greatly appreciated. Below is my full code, with working functions and then the one that is not working and below that is my mongodb output (albeit wrong):
CampRepository = function(){};
CampRepository.prototype.addOwner = function(owner, callback){
console.log(db);
db.owners.save(owner, function(err, saved){
if (err || !saved) {
console.log('broke trying to add owner : ' + err);
callback(err);
} else {
console.log('save was successful');
callback(null, saved);
}
});
};
CampRepository.prototype.addCamp = function(ownerEmail, camp, callback){
db.owners.update(
{email: ownerEmail},
{$push: {
camps:{
name: camp.name,
location: camp.location,
managerName: camp.managerName,
managerEmail: camp.managerEmail,
managerPassword: camp.managerPassword,
managerPayRate: camp.managerPayRate,
instructors: [],
students: []
}
}
}, function(err, saved){
if (err || !saved) {
console.log('broke trying to add camp ' + err);
callback(err);
} else {
console.log('save was successful');
callback(null, saved);
}
});
};
/*
THIS IS THE ONE THAT DOESN'T WORK
*/
CampRepository.prototype.addInstructor = function(ownerEmail, campName, instructor, callback){
db.owners.update(
{email: ownerEmail, 'camps.name': campName},
{$push: {
camps:{
instructors: {
firstName: instructor.firstName,
lastName: instructor.lastName,
email: instructor.email
},
}
}
}, function(err, saved){
if (err || !saved) {
console.log('broke trying to add camp ' + err);
callback(err);
} else {
console.log('save was successful');
callback(null, saved);
}
});
};
OUTPUT
{
"_id" : ObjectId("51c7b04d2746ef6078000001"),
"email" : "john.smith#gmail.com",
"firstName" : john,
"lastName" : smith,
"password" : "mypassword",
"camps" : [
{
"name" : "cubs-killeen",
"location" : "killeen",
"managerName" : "bill jones",
"managerEmail" : "bill#gmail.com",
"managerPassword" : "secretpasscode",
"instructors" : [ ],
"students" : [ ]
},
{ "instructors" : { "name" : "jon tisdale" } }
]
}
You might need to take a look at this. you can achieve this using dot.notation
It's very powerfull way to find or update items in a larger array of document scheme. If you still not able to achieve this i would happy to provide you the following code...
I've inserted a new owner2
owner2 = {
email : 'murali.ramakrishnan#gmail.com',
password : 'mypassword',
firstName : 'murali',
lastName : 'ramakrishnan',
camps : [
{
name : 'Rotary club',
location : 'trichy',
manager : {name: 'baskaran', email: 'baskaran#mit.edu', password: 'baskaran'},
instructors : [
{
firstName : 'baskaran',
lastName : 'subbiah',
classes : []
},
{
firstName : 'david',
lastName : 'nover',
classes : [],
},
],
students : []
}
]};
If you see we just need to add a new instructor as requested...
let first add the document to the collection
db.try.insert(owner2);
here you go you have added a new document
now, i'm going to create a new instructor object to insert #newly created owner2
instructor1 = {
firstName : 'lakshmi',
lastName : 'kanthan',
classes : []
};
above is the document object for new instructor
you can perform this update in many ways, using mongodbs methods like
collection.update
collection.findAndModify
if you want to insert or update any value to the sub-document we need to find using a dot.notation and push the sub-document to the document, here the code
db.try.update(
{'camps.name': "Rotary club" },
{
$push: { 'camps.$.instructors' : instructor1 }
}
)
the above code inserts a new record under the instructor field as in the field an array it just pushes the sub-document
End-Result
{
"_id" : ObjectId("51c7b222c0468dc711a60916"),
"email" : "murali.ramakrishnan#gmail.com",
"password" : "mypassword",
"firstName" : "murali",
"lastName" : "ramakrishnan",
"camps" : [
{
"name" : "Rotary club",
"location" : "trichy",
"manager" : {"name": "baskaran", "email": "baskaran#mit.edu", "password": "baskaran"},
"instructors" : [
{
"firstName" : "baskaran",
"lastName" : "subbiah",
"classes" : []
},
{
"firstName" : "david",
"lastName" : "nover",
"classes" : [],
},
{
"firstName" : "lakshmi",
"lastName" : "kanthan",
"classes" : [],
}
],
"students" : []
}
]};

Categories