MongoDB: how can I find and merge array - arrays

I'm trying to find a specific ID in my document and then merge an array to the existing one, for example if I have this array stored in db.friends:
["12","13","14"]
and I send this array: ["12","16","18"], db.friends should contain: ["12","13","14","16","18"]
I'm using underscore library, but I'm not sure I have to (maybe "aggregate" in mongoose?)
Here is what I did, can you tell me where am I wrong?
function saveFollowers(req, res) {
var friends = req.body.friends; // the new array to merge ["54aafe9df4ee360300fc94c7"];
User.findOne({_id: req.user._id}).exec(function (err, user) {
if (err) {
res.jsonp({error: "Error fetching user info"})
} else {
friends = _.extend(friends, user.friends); //user.friends=existing friends we have in db
user.save(function (err) {
if (err) { res.jsonp({error: "Cant save"}); }
console.log("Friends NOW:"+JSON.stringify(friends)); //Here I don't see the merge, also, I can't see it in mongo db.
res.jsonp("success");
});
}
});
Thank you!

With your current implementation, you haven't actually modified the friends key in the returned user object. So rather you can use the union method as
user.friends = _.union(friends, user.friends); //user.friends=existing friends
user.save(function (err) { .. }
Or with ES6 using the spread operator for concatenating the array and Set for creating a distinct set of elements:
user.friends = [...new Set([...friends ,...user.friends])];
user.save(function (err) { .. }
Another alternative is using the aggregation framework, you could utilize the $setUnion operator:
function saveFollowers(req, res) {
var friends = req.body.friends; // the new array to merge ["54aafe9df4ee360300fc94c7"];
User.aggregate([
{ "$match": { _id: req.user._id } },
{
"$project": {
"friends": { "$setUnion": [ "$friends", friends ] }
}
}
]).exec(function (err, results){
if (err) {
res.jsonp({error: "Error fetching user info"})
} else {
User.findByIdAndUpdate(req.user._id,
{ "$set": { "friends": results[0].friends } },
{ "new": true },
function (err, user) {
if (err) { res.jsonp({error: "Cant save"}); }
console.log("Friends NOW: "+ JSON.stringify(user.friends));
res.jsonp("success");
}
);
}
});
}

Related

how to push element into array inside array in mongodb while updating the sibling field of parent array in document

Hell devs, Here is my document schema
var Schema = mongoose.Schema;
var botSchema = new Schema({
Bot_name: String,
UserName:String,
Modules: [{
ModuleStatement: String,
ModuleID: String,
ModuleResponse: [{
Response: String,
TransBotID: String
}]
}]
});
what i want to do is update the ModuleStatement as well as push the element into ModuleResponse setting Response and TransBotID to some values
I tried following but it only updates the ModuleStatement and doesn't push element into ModuleResponse
botSchema.update({ 'Modules.ModuleID': req.body.ModId }, { '$set': { 'Modules.$.ModuleStatement': req.body.Statement } }, function (err, data) {
if (err) {
throw err;
} else {
botSchema.update({ "Modules.ModuleID": req.body.ModId }, { "$push": { "ModuleResponse": { "Response": req.body.Statement, "TransBotID": req.body.transitmod } } }, function (err, data) {
if (err) {
throw err;
}
else {
res.json('upgraded');
}
})
}
})
how can i push element into ModuleResponse while setting the ModuleStatement at the same time?
$push is only available in the $group stage. You may want to try as the following:
botSchema.find({'Modules.ModuleID': req.body.ModId}, (err, bots) => {
if (err) {
throw err;
} else {
bots.forEach((bot) => {
bot.modules.forEach((botModule) => {
if (botModule.ModuleID == req.body.ModId) {
botModule.Statement = req.body.Statement;
botModule.ModuleResponse.push({
Response: req.body.Statement,
TransBotID: req.body.transitmod
})
}
});
bot.save((err, data) => {
if (err) throw err;
});
});
res.json('upgraded');
}
})
Here you have a shell code:
db.bot.update(
{ "Modules.ModuleID": "<some_id>" },
{
"$set": { "Modules.$.ModuleStatement": "<some_statement>" },
"$push": {
"Modules.$.ModuleResponse": {
"Response" : "<some_response>",
"TransBotID" : "<some_trans_id>"
}
}
}
)
The thing is that you can have more than one update expressions in one update document. I believe you can convert it to mongoose quite easily.

Can't compare MongoDB data with javascript array

I want to compare the data which I got from Mongo to javascript array. I am using lodash to compare. But it always return incorrect result.
var editUser = function(userData, getOutFunction) {
var status = CONSTANTS.NG;
checkExistUser(userData._id).then(function(user) {
if (user !== null) {
var userGroup = JSON.stringify(user.group);
user.group = user.group.map((groupId) => {
return groupId.toString();
});
var removedGroups = _.difference(userGroup, userData.group);
var addedGroups = _.difference(userData.group, userGroup);
console.log('Removed Groups: ', removedGroups);
console.log('Added Groups: ', addedGroups);
} else {
status = CONSTANTS.NG;
logger.debug(DEBUG_CLASS_NAME, "Cannot find object");
if (typeof(getOutFunction) !== 'undefined') {
getOutFunction(status, null);
} else {
NO_CALLBACK();
}
}
}).catch(function() {
console.log('Promise is error');
});
var checkExistUser = function(userId) {
return new Promise(function(resolve, reject) {
UserDAO.findById(userId, function(err, user) {
if (err) {
logger.debug(DEBUG_CLASS_NAME, {
name: err.name,
code: err.code,
message: err.message,
method: "checkExist"
});
resolve(null);
} else {
resolve(user);
}
});
});
}
For example:When I try to input value for lodash difference function
var user.group = ["58b8da67d585113517fed34e","58b8da6ed585113517fed34f"];
var userData.group = [ '58b8da67d585113517fed34e' ];
I want lodash difference return below result:
Removed Groups: ['58b8da6ed585113517fed34f']
Added Groups: []
However, the function gave me the result like:
Removed Groups: []
Added Groups: [ '58b8da67d585113517fed34e' ]
Can anyone help me in this case?
I will do appreciate it.
I have had this issue as well, the result from mongodb is an ObjectId type so you can compare the someObjectId.toString() value with your array of strings, or you could use
someObjectId.equals(stringOrObjectIdValue)
However, if you want to keep using lodash functions you will either have to force both arrays to strings or to ObjectIds before passing them into the function.

CloudantDB & NodeJS: Query data with specific id

I just created a NodeJS cloudantDB web starter on bluemix. Then, I have a API get data from cloudantDB and get successfull but it returns all data. Please see js file:
js file:
app.get('/api/provider', function(request, response) {
console.log("Get method invoked.. ")
db = cloudant.use(dbCredentials.dbProvider);
var docList = [];
var i = 0;
db.list(function(err, body) {
if (!err) {
var len = body.rows.length;
console.log('total # of docs -> '+len);
if(len == 0) {
// error
} else {
body.rows.forEach(function(document) {
db.get(document.id, { revs_info: true }, function(err, doc) {
if (!err) {
if(doc['_attachments']) {
// todo
} else {
var responseData = createResponseDataProvider(
doc._id,
doc.provider_type,
doc.name,
doc.phone,
doc.mobile,
doc.email,
doc.logo,
doc.address
);
}
docList.push(responseData);
i++;
if(i >= len) {
response.write(JSON.stringify(docList));
console.log('ending response...');
response.end();
}
} else {
console.log(err);
}
});
});
}
} else {
console.log(err);
}
});
If I want to add parameter to API to get specific data from DB , Do we need create search index or query on cloudant, afer that call API the same : app.get('/api/provider/:id'). Please help me review and sharing. Thanks
you could get the document by id/name:
db.get(docID, function(err, data) {
// do something
});
references:
https://github.com/apache/couchdb-nano#document-functions
https://github.com/cloudant/nodejs-cloudant#api-reference
You can use a search function of Cloudant.
You need to create search index. In search index you can manage what data you want to get.
Example: https://cloudant.com/for-developers/search/
Following this code after create search index.
...
var query = {q: "id:doc.id"};
db.search('design document name', 'index name', query, function(er, result) {
if (er) {
throw er;
}
console.log(result);
});

How to clear an array in MongoDB

I have an emails object that contains an array in a mongodb database. However, when I try to use $set to make the array empty it doesn't work. How am I supposed to clear the array?
exports.clearEmails = function(req, res, next) {
var listId = req.params.id;
var errors = req.validationErrors();
if (errors) {
return res.status(400).send(errors);
}
EmailList.update({'_id': listId}, {$set: {'emails': []}}, function(err,results) {
if (err) {
return res.status(400).send(err);
} else {
return res.status(200).send(results);
}
});
}

NodeJS - Removing a particular item from an Array

I'm getting list of all collections from mongodb, in form of an array
mongoose.connection.db.listCollections().toArray(function (err, names) {
if (err) {
console.log(err);
}
console.log(names);
output:
[ { name: 'system.indexes' },
{ name: 'books' },
...
I want to remove that system.indexes from the array. I tried playing around with some functions like:
Splice
Pop, Shift
Underscore's withoutfunction
Well, Honestly I don't even know if they were intended for this.
To remove the objects where name is equal to system.indexes do it as follow:
mongoose.connection.db.listCollections().toArray(function (err, names) {
if (err) {
console.log(err);
}else{
var i;
for(i=names.length - 1; i >= 0; i-=1){
if(names[i].name !== 'system.indexes'){
names.splice(i,1);
}
}
// names now contain all items without the system.indexes
}

Resources