how to nest mongodb queries through node.js? - javascript

I am having a collection of users of the type -
{
"_id" : ObjectId("56f60e4eea8af4670408483e"),
"twitterHandle" : "shrutip",
"firstName" : "Shruti",
"lastName" : "Patil",
"emailID" : "shrutip#gmail.com",
"password" : "91382451347786e9b8f2f3817b27a2adfec1880c",
"phoneNumber" : "98739458789",
"location" : "San Jose",
"birthYear" : 1992,
"birthMonth" : 1,
"birthDay" : 10,
"followers" : [
"abhayp",
"anupd",
"lubdhal",
"poojag",
"prashantb",
"pratiksanglikar",
"shaileshyedge",
"shrutip"
],
"following" : [
"abhinavk",
"anupd",
"hiteshn",
"lubdhal",
"omkarn",
"poojag",
"pratiksanglikar",
"shaileshyedge",
"shrutip"
],
"tweets" : [
{
"tweet_id" : "3c50e98cf0c2298f40f98a013cd4a18a1443b7ac",
"tweet_text" : "At BJP youth wing meet, seniors worry over #JNU controversy, and not #RamTemple.",
"createdOn" : ISODate("2016-03-07T23:37:27Z"),
"tags" : [
"JNU",
"RamTemple"
]
}
]
}
I want to create feed (all tweets of the users the given user is following in ascending order of date) for any given user. I got the list of users which the given user is following, but I need to find the tweets of the found users. How do I do it in node.js? How to nest these queries?
What I've done so far is listed below -
var cursor = MongoDB.collection("users").find({
"twitterHandle": twitterHandle
});
cursor.each(function(err, doc) {
assert.equal(err, null);
if (doc != null) {
var followingCursor = MongoDB.collection("users").find( { twitterHandle: { $in: doc.following } } );
followingCursor.each(function (err, following) {
if(following != null) {
feed.push(following.tweets);
}
});
promise.resolve(feed);
}
});
But somehow, the promise gets resolved before the second query executes.
How do I ensure that all the iterations of followingCursor.each are executed before I return the promise?

Eventually I found out the answer myself.
if (doc != null) {
var followingCursor = MongoDB.collection("users").find( { twitterHandle: { $in: doc.following } } );
followingCursor.each(function (err, following) {
if(following != null) {
feed.push(following.tweets);
}
});
promise.resolve(feed);
}
In the above code, promise should be resolved if the following != null condition fails.
Apparently MongoDB driver returns null when the values in cursor end. The correct code is as following -
if (doc != null) {
var followingCursor = MongoDB.collection("users").find( { twitterHandle: { $in: doc.following } } );
followingCursor.each(function (err, following) {
if(following != null) {
feed = feed.concat(following.tweets);
} else {
promise.resolve(feed);
}
});
}

Related

How to update all nested documents of an array in a selected document in mongoose?

In a situation I need to update a field of all documents nested in an array in Mongoose model.
I add a new nested document of uploaded image to Users collection and I need to set "is_available" of all previous documents to be false and only "is_available" field of newly inserted document to be true.
All I searched and found was about updating a nested document with specific id or filter. but I didn't find a way to update a specific field of all nested documents of an array in a Model.
My Model:
var mongoose = require("mongoose");
var Schema = mongoose.Schema;
var UsersSchema = new Schema({
name: { type: String, default: "" },
lastname: { type: String, default: "" },
images: [{
dir: { type: String },
is_available: { type: Boolean }
}]
});
var Users = mongoose.model("Users", UsersSchema, "users");
module.exports = Users;
Actual result:
{
"_id" : ObjectId("5ce950aa4sw435ty503ab83b"),
"name" : "Sina",
"image" : [
{
"_id" : ObjectId("5cf4dd3da6b4gb6bcf9c6dc1"),
"dir" : "profiledirectory/804eafeaf8acc40a3d6.jpg",
"is_available" : true
},
{
"_id" : ObjectId("5cf4fffs2419316bddffgg82"),
"dir" : "profiledirectory/d85b01ac40fa6b1a7c1.jpg",
"is_available" : true
},
{
"_id" : ObjectId("5cf4ff334fhd316bef2fdt40"),
"dir" : "profiledirectory/512d9d19da7a4322b37.jpg",
"is_available" : true
}
]
}
Expected Result:
{
"_id" : ObjectId("5ce950aa4sw435ty503ab83b"),
"name" : "Sina",
"image" : [
{
"_id" : ObjectId("5cf4dd3da6b4gb6bcf9c6dc1"),
"dir" : "profiledirectory/804eafeaf8acc40a3d6.jpg",
"is_available" : false
},
{
"_id" : ObjectId("5cf4fffs2419316bddffgg82"),
"dir" : "profiledirectory/d85b01ac40fa6b1a7c1.jpg",
"is_available" : false
},
{
"_id" : ObjectId("5cf4ff334fhd316bef2fdt40"),
"dir" : "profiledirectory/512d9d19da7a4322b37.jpg",
"is_available" : true
}
]
}
Code Snippet:
let updateQuery = {
$set: { 'image.$.is_available': false },
$push: {
image: [
{
dir: "profiledirectory/558bb6938ecd54bde556af122a4.jpg",
is_available: true
}
]
}
}
let findQuery = { _id: req.body.user_id }
Users.findOneAndUpdate(findQuery,
updateQuery, function (err, doc) {
if (err) {
res.send(err.message)
} else {
res.send('successful')
}
})
According to what you've mentioned, you keep adding objects to image field dynamically, and each time you add the new object, the existing objects should be overridden with is_available:false
eventObject.find(query).lean().exec(function (err, response) {
if (err) {
logger.error(err);
return reject(err.message)
}
// Assuming there will be only one record based on the query you make
if(response.length>0){
response[0].images = response.images.map((image)=>{
image.is_available = false
return image
})
// Now append your new image to the modified response
response[0].images.push(newimage)// this should be the newImage object
// Now use findOneAndUpdate to update the existing doc by querying with id or according to your usecase
eventObject.findOneAndUpdate(query, response[0], { upsert: true }, (err, data) => {
if (err) {
return reject(err)
}
logger.info(data);
return resolve(newData);
})
}
})
So the basic approach is,
Get the doc from the DB
Update the content of the doc
Add the new data
update the record with updated data.
after you uploaded file , you have to find user
// after upload image
User.findOne({_id:req.user._id}).lean().exec((err,user)=>{
if(!err && user){
// setting all previous images to false
user.image.forEach(image=>{
image.is_available=false;
});
// now pushing new uploded item to image array
let newImage={"dir" : "path of uploaded item here" , "is_available" : true};
user.image.push(newImage);
user.save((err,updated)=>{
if(!err && updated){
return res.status(200).json({status:"success",message:"User updated"});
}
});
}
});

MongoDB Check if a document/record exists

Im trying to use .find({}) with mongogb and unfortunately its not giving me the response I was expecting, I'm unsure how to check if the document exists or not? What I'm trying to do is say:
If a document does exist then do something.. IE send a response back
but If a document doesn't exist then create the document,
unfortunately I know that a document doesnt exist yet it must be picking up the wrong thing with 'if (docs)' but then when I change it to something else then it always creates records!?
The code:
addRefund : (refundCalc, callback) => {
order_number = refundCalc.refundDetails.customer_details.order.order_number;
dbconnect.createConnection()
refund.find({order_number: order_number}, (err, docs) => {
if (docs) {
console.log('docss!!!!!!!!!!!!!' + JSON.stringify(docs));
console.log('calling within error!!!!!!')
let notStored = {"refundDocStored" : "False"}
callback(notStored)
dbconnect.closeConnection();
}
else {
refund.create(refundCalc).then((refunddoc) => {
let filestored = {"refundDocStored" : "True"}
dbconnect.closeConnection();
callback(filestored)
}).catch((err)=> {
console.log(err);
dbconnect.closeConnection();
})
}
})
},
the schema:
const refundSchema = new Schema({
domain : { type: String},
refundDetails : {
customer_details : [],
refund : {
shipping : {
amount : { type: Number},
tax : {type : Number},
maximum_refundable : {type : Number}
},
refund_line_items: [],
transactions: []
}
}
});
The orders are stored within the refundDetails like this:
"refundDetails":{"customer_details":{"order":{"order_number":1021
It simply doesnt seem to work for me! if a document exists i cant seem to actually prove that it does?
Any help would be great, thanks!
You are using the wrong search query. You are searching for order_number which is a property of an object inside another object. You have to reference the order_number full path in your query i.e {"refundCalc.refundDetails.customer_details.order.order_number" : order_number}
addRefund : (refundCalc, callback) => {
order_number = refundCalc.refundDetails.customer_details.order.order_number;
dbconnect.createConnection()
refund.find({"refundCalc.refundDetails.customer_details.order.order_number": order_number}, (err, docs) => {
if (docs) {
console.log('docss!!!!!!!!!!!!!' + JSON.stringify(docs));
console.log('calling within error!!!!!!')
let notStored = {"refundDocStored" : "False"}
callback(notStored)
dbconnect.closeConnection();
}
else {
refund.create(refundCalc).then((refunddoc) => {
let filestored = {"refundDocStored" : "True"}
dbconnect.closeConnection();
callback(filestored)
}).catch((err)=> {
console.log(err);
dbconnect.closeConnection();
})
}
})
},

Firebase v3 Query by Grandchild

When registering new email/password type users, I need to make user that the displayName that they enter does not already exist in my Realtime Database before calling .createUserWithEmailAndPassword. So I need a query. I need to get a list of all displayName's in my users branch. I am confused as to how to gather this for each user which is denoted by each users auth.uid.
What would the retrieval look like? I am thinking something like:
firebase.database().ref('users/' + allUserIds).equalTo('Joe');
but I know that allUserIds is not valid. Can someone help me with this?
{
"users" : {
"6mJb9vtpbDelyyjirKEf6sSEj8h1" : {
"name" : "asdfs#asdf.com",
"provider" : "password",
"displayName" : "Joe"
},
"T7D7qEOPPHXjKSzglKheGJDQNkE3" : {
"name" : "gfdsdf#hlkjh.com",
"provider" : "password",
"displayName" : "Jane"
},
"kTG9R0V4aXYsogQfgF633KFYtzV2" : {
"name" : "Andre3000",
"provider" : "google.com",
"displayName" : "Andre"
}
}
}
You'd use Firebase queries for that:
var users = firebase.database().ref('users');
var joes = users.orderByChild('displayName').equalTo('Joe');
joes.once('value', function(snapshot) {
console.log('A Joe does '+(snapshot.exists()?'':'not ')+' exist')
});
Don't forget to define an index on users:
{
"rules": {
"users": {
".indexOn": "displayName"
}
}
}
Just thought I'd share my somewhat fleshed out solution. Call with myApp.displayNameExists('Joe').
var myApp = (function() {
var pub = {};
pub.displayNameExists = function(name) {
var users = firebase.database().ref('users');
var duplicate = users.orderByChild('displayName').equalTo(name);
duplicate.once('value').then(function(snap) {
if (snap.val()) {
console.log('found. ask for new display name');
} else {
console.log('name unique. ok to write this user to db');
}
}, function(error) {
// The Promise was rejected.
console.error(error);
});
}
//API
return pub;
}());

I am trying to iterate through an array of ids and insert a mongodb document if an id is not present. How can i get them to persist?

I am working with Node JS and mongodb and I have a collection of documents with ids from 1-5000. However there are some ids that are missing and I want each document to have one ID.
Here is the code I'm working with:
MongoClient.connect("mongodb://localhost:27017/test", function(err, db) {
if(err) {
console.log("Unable to connect", err);
return;
}
console.log("We are connected");
var collection = db.collection('examples');
collection.aggregate(
[
{"$sort": {"user_id": 1} },
{"$out": "users"}
]
).toArray(function(err, docs) {
var toSave = [];
db.collection('users').find().toArray(function(err, docs){
docs.forEach(function(doc){
toSave.push(doc.user_id);
})
for (var i = 1; i < 5000; i++) {
if (toSave.indexOf(i) == -1) {
db.collection('examples').insert({
user_id: i,
create_dt: new Date()
})
}
}
console.log(toSave);
db.close()
})
});
});
I was hoping this would go through my toSave array and insert documents for each of the missing user_id's but when I check my database it only ever creates one document.
How can I get all of the documents to save in the database?
I agree with #Blakes. It appears to me that you really want to find documents containing a user_id field which must be updated, and then update that field with some appropriate value. For example, the user_id field might be null, or it contains a duplicate value. Suppose you have two documents that each have a user_id of 81:
{ "_id" : ObjectId("56c519bac62ffdbd22b000fd"), "user_id" : 81, "stuff" : 11 }
{ "_id" : ObjectId("56c519cbc62ffdbd22b000fe"), "user_id" : 81, "stuff" : 12 }
Changing the user_id field can be done by calling the updateOne() method of the MongoDB javascript driver.
Here is example code:
db.collection('examples2').find(query).toArray(function(err, docs) {
if (err) throw (err)
docs.forEach(function (doc) {
if (doc.user_id === 81) {
dcnt++
im_array.push(doc._id)
console.dir(doc)
}
if (doc.user_id === "") { //empty?
dcnt++
im_array.push(doc._id)
console.dir(doc)
}
})
})
setTimeout(function() {
console.log("\nPrinting list of objectids\n")
for (var i = 0; i < im_array.length; i++) {
console.log(im_array[i])
}
console.log("\nUpdating Documents...\n")
for (var j = 0; j < im_array.length; j++) {
idObj = new ObjectID(im_array[j])
db.collection('examples2').updateOne( { "_id" : idObj }, { "$set" : { "user_id" : j + 27 } }, function(err2, doc2) {
if (err2) throw err2
})
}
}, 5000)
setTimeout(function() {
db.collection('examples2').find( { "user_id" : 10 })
console.log('\nTotal number of documents processed ' + dcnt + '\n')
db.close()
}, 12000)
Since processing is asynchronous, I'm being a bit crude and using setTimeout() where perhaps using promises-based processing is better.
In any case, the above code will update the documents containing a user_id field equal to 81:
{ "_id" : ObjectId("56c519bac62ffdbd22b000fd"), "user_id" : 27, "stuff" : 11 }
{ "_id" : ObjectId("56c519cbc62ffdbd22b000fe"), "user_id" : 28, "stuff" : 12 }
Consider creating a unique index on the user_id field as well. This way, any code that attempts to create or update a document without including a properly formatted user_id will fail.

mongodb updating only specific subelements

my db structure looks like:
{
"_id" : ObjectId("51e66873f6a6600436000001")
,"email" : "asd#asd.de",
,"attribute_group_a" : {
"attribute_a" : ""
,"attribute_b" : ""
,"attribute_c" : ""
,"attribute_d" : ""
},
,"attribute_group_b" : {
"attribute_subgroup_b_a" : {
"attribute_a" : ""
,"attribute_b" : ""
,"attribute_c" : ""
,"attribute_d" : ""
}
,"attribute_subgroup_b_b" : {
"attribute_a" : ""
,"attribute_b" : ""
,"attribute_c" : ""
,"attribute_d" : ""
}
}
}
so lets say i want to update att_subgrp_b_a:
exports.updateProfil = function(req, res, item, callback) {
var email = req.session.email;
db.collection('profiles', function(err, collection) {
collection.update({"email": email},{$set: item}, function(err, result)
the var "item" looks like:
{
attribute_group_b:
{
attribute_subgroupgroup_b_a:
{
att_a: "xy"
,att_b: "xy"
}
}
}
when i now update the file => it deletes everything in attr_group_b and replaces it with "item"
that means attr_subgrp_b_b is totally gone and all other attributes (of attr_subgrp_b_a) that weren't updated
i want that it looks for the attributes in "item", replaces them into db letting all other obj untouched
Try the query below
var email='emailid';
var item='whichuwanttoupdate';
collection.update(
{"email": email},
{$set:{'attribute_group_b.attribute_subgroup_b_a':item}},
function(err,result){
});

Categories