Mongodb 3.2 Node js $push is not working - javascript

I want to push new friend JSON object to an array : friend
I have try $push directly via mongodb but it is not working on NodeJS
Anyone know want is going wrong?
I have try UsersInfo.friend -> friend UsersInfo.friend.user_id -> user_id
and no err return.
The Structure of Player :
socket.on('follow_friend',function(data){
var me = current_players_socket.indexOf(socket);
console.log("PLayer id:"+data.user_id+" Player name:"+current_players[me].name+ "'s friend following request received");
console.log("Target:"+data.fdid);
MongoClient.connect(url,function(err,db){
assert.equal(null,err);
follow_friend_to_db(data,db,function(){
db.close();
});
});
});
var follow_friend_to_db = function(data,db,callback){
var me = current_players_socket.indexOf(socket);
console.log("Following "+data.fdid+" to "+data.user_id);
current_players[me].friend.push(data.fdid);
db.collection('Users').update(
{"UsersInfo.user_id":data.user_id},
{
$push: {
"UsersInfo.friend" :
{$each:
{
"UsersInfo.friend.user_id" : data.fdid,
"UsersInfo.friend.add_date" : new Date("2014-10-01T00:00:00Z")
}
}
}
},function(err,results){
for(i= 0;i<current_players[me].friend.length;i++){
console.log(current_players[me].friend[i]);
}
socket.emit('friend_followed',{fdid:data.fdid});
callback();
});
};
here is the $set function which is work
socket.on('gold_add',function(data){
console.log("Player id:"+data.user_id+" add gold request recevied");
var i = current_players_socket.indexOf(socket);
MongoClient.connect(url,function(err,db){
assert.equal(null,err);
update_user_gold_to_db(data,db,function(){
db.close();
});
});
console.log("Player:"+current_players[i].get_name()+"'s gold:"+current_players[i].gold);
});
var update_user_gold_to_db = function(data,db,callback){
var i = current_players_socket.indexOf(socket);
console.log("Player id:"+data.user_id+" add gold amount:"+data.amount);
var t = data.amount + current_players[i].get_gold();
console.log(t);
db.collection('Users').update(
{"UsersInfo.user_id":data.user_id},
{
$set:{"UsersInfo.gold":t}
}, function(err,results){
//console.log(results);
current_players[i].gold+=data.amount;
socket.emit('gold_add_success',{gold:current_players[i].gold});
callback();
});
};

Why are you using $each. We use $each when we have an array to push like mentioned in mongodb documentation:
db.inventory.update(
{ _id: 2 },
{ $addToSet: { tags: { $each: [ "camera", "electronics", "accessories" ] } } }
)
Try removing $each:
var follow_friend_to_db = function(data,db,callback){
var me = current_players_socket.indexOf(socket);
console.log("Following "+data.fdid+" to "+data.user_id);
current_players[me].friend.push(data.fdid);
db.collection('Users').update(
{"UsersInfo.user_id":data.user_id},
{
$push: {
"UsersInfo.friend" :
{
"user_id" : data.fdid,
"add_date" : new Date("2014-10-01T00:00:00Z")
}
}
},function(err,results){
for(i= 0;i<current_players[me].friend.length;i++){
console.log(current_players[me].friend[i]);
}
socket.emit('friend_followed',{fdid:data.fdid});
callback();
});
};

Related

Updating info with Mongoose, array inside object inside object dynamically

I'm trying to update the JSON field "champ_x" from 1 to 3 and for both players 1 at a time in a dynamic function:
{
"_id": {
"$oid": "58a3521edf127d0a0c417cda"
},
"room": "room_0.0940045412694186",
"player_1": "eee",
"player_2": "fff",
"player_1_details": {
"history_moves": [],
"champions": [
{
"champ_1": "na"
},
{
"champ_2": "na"
},
{
"champ_3": "na"
}
]
},
"player_2_details": {
"history_moves": [],
"champions": [
{
"champ_1": "na"
},
{
"champ_2": "na"
},
{
"champ_3": "na"
}
]
},
"game_state": "789",
"__v": 0
}
I've got this model:
match_schema.statics.update_champ = function(room, turn, champ_num, champ_select, callback){
if(champ_num == "champ_1"){
match_mongoose.update({ room: room }, { $set: { 'player_1_details.champions.0.champ_1': champ_select}})
.exec(function(error){
if(error){ return callback(error); }else{ return callback(null); }
});
}
};
This model works fine
My problem is, I'm trying to make it dynamic, in which I can just send through the function parameters the current turn(1 or 2), and the chosen position(champ_1,2, or 3).
I've tried this:
//Update Champion
match_schema.statics.update_champ = function(room, turn, champ_num, champ_select, callback){
match_mongoose.update({ room: room }, { $set: { 'player_'+turn+'_details.champions.0.'+champ_num: champ_select}})
.exec(function(error){
if(error){ return callback(error); }else{ return callback(null); }
});
};
var match_mongoose = mongoose.model('matches', match_schema, 'matches');
module.exports = match_mongoose;
But I get an error that says the "Unexpected token +" seems like concatenating the value doesn't work. Is there a way to do this?
Thanks!
You may build the $set modifier and the match part as suggested by #dNitro :
var modifier = { $set: {} };
modifier.$set['player_' + turn + '_details.champions.$.champ_' + champ_num] = champ_select;
You will have also an issue with array index, you specify champions.0 so it will always take the first array item which won't match for champs_2 & champs_3. One solution for this is to use positional parameter $ with a match from the array :
var match = {};
match['room'] = room;
match['player_' + turn + '_details.champions.champ_' + champ_num] = { $exists: true };
The full update function is :
matchSchema.statics.update_champ = function(room, turn, champ_num, champ_select, callback) {
var modifier = { $set: {} };
modifier.$set['player_' + turn + '_details.champions.$.champ_' + champ_num] = champ_select;
var match = {};
match['room'] = room;
match['player_' + turn + '_details.champions.champ_' + champ_num] = { $exists: true };
this.update(match, modifier)
.exec(function(error) {
if (error) {
return callback(error);
} else {
return callback(null);
}
});
};
And calling it with :
Match.update_champ("room_0.0940045412694186", 1, 1, "new_value", function(err, res) {
if (!err) {
console.log(err);
return;
}
console.log(res);
});
You can find a full example here

MongoDB $pull not working

I am building a Meteor app and I have Contests/Entries collections. When someone enters the contest, their user_id is pushed into the Contest.entered_users array with $addToSet. Here is the code:
entryInsert: function(entryAttributes) {
check(Meteor.userId(), String);
check(entryAttributes, {
contest_id: String
});
var user = Meteor.user();
var entry = _.extend(entryAttributes, {
user_id: user._id,
user_name: user.profile.name,
submitted: new Date(),
submitted_day: moment().format('MMM D')
});
var currentContest = Contests.findOne(entryAttributes.contest_id);
// Check to make sure that the person has not already entered the giveaway
if (currentContest.entered_users.indexOf(entry.user_id) !== -1) {
throw new Meteor.Error('invalid', "You have already entered the giveaway");
} else {
Contests.update(
currentContest._id,
{
$addToSet: {entered_users: entry.user_id},
$inc: {entries: 1}}
);
}
// Create entry in order to get the entry id
var entryId = Entries.insert(entry, function(err) {
if (err) {
alert(err.reason);
}
});
return {
_id: entryId
}
}
I want to remove a persons user_id from the Contest.entered_users array when an entry is removed. I am trying to use $pull but it doesn't appear to be working... When I remove an entry, the entry.user_id is still in the contest.entered_users array. Here is the relevant code:
'click .entry-delete': function(e, tmpl) {
e.preventDefault();
var currentEntry = this;
var currentEntryId = this._id;
var contestId = Contests.findOne(currentEntry.contest_id);
// Update the contest by removing the entry's useer_id from entered_users
Meteor.call('contestRemoveEntry', contestId, currentEntry, function(error) {
if (error) {
alert(error.reason);
}
});
Meteor.call('entryRemove', currentEntryId, function(error) {
if(error) {
alert(error.reason);
}
});
}
Here is the contestRemoveEntry method:
contestRemoveEntry: function(contestId, currentEntry) {
Contests.update({ _id: contestId }, { $pull: { entered_users: currentEntry.user_id } } );
}
Any ideas as to why this is not working? I've tried other SO solutions but nothing seems to be working.
It appears that this is the correct way to make $pull work:
Contests.update(contestId, { $pull: { entered_users: currentEntry.user_id } } );

MongoDB increment number in subdocument

My mongoDB document looks like this:
{
valOne: "one",
valTwo: "two",
valThree: {
threeOne: 0,
threeTwo: 0
}
}
i would like to increment either "threeOne" or "threeTwo" depending on the user request.
My code so far:
var whichFieldToUpdate = request.body.field; //can be either threeOne or threeTwo
var id = new BSON.ObjectID(request.body.id); //contains document id
db.collection('name').update({_id: id}, {$inc: { ?????? } },
function(err, result) {
});
???? should be something like this: {$inc: {valThree: {whichFieldToUpdate : 1 } }
var field = 'valThree.' + request.body.field;
var inc = {};
inc[field] = 1;
db.collection('name').update({_id: id}, {$inc: inc } },
function(err, result) {
});

How can I assign a operator to variable

I am working on like and unlike section of an image. When a user likes an image, it pushes the userID to an array in mongodb. When a user unlikes an image, it removes the userID from the array. I am trying to do it using $addToSet and $pull.
Question: How can I do it in a single block instead of writing two separate bolcks for these two? Currently I am using a variable opr but it is not working. How can I make it work?
if(likeAction == "like"){
var opr = '$addToSet'
}
else if(likeAction == "unlike"){
var opr = '$pull'
}
Like.update(
{ imageID: imageID },
{ opr : { userIDs: userID } },
function(err){
if(!err){
Like.findOne({imageID : imageID}, function(err,like){
image.likeCount = like.userIDs.length
image.save(function(err){
if(!err){
return res.send({
status: {
error: 0,
message: "Successful"
}
})
}
})
})
}
}
);
I think this should work to combine both queries and solve the opr issue:
var update = {};
if (likeAction === 'like'){
update.$addToSet = { userIDs: userID };
update.$inc = { likeCount : 1 };
} else if (likeAction === 'unlike'){
update.$pull = { userIDs: userID };
update.$inc = { likeCount : -1 };
}
Like.update({ imageID: imageID }, update, ...);
You can do something like that :
var opr, updateCommande = {};
if(likeAction == "like"){
opr = '$addToSet'
}
else if(likeAction == "unlike"){
opr = '$pull'
}
updateCommande[opr]= { userIDs: userID }
Like.update(
{ imageID: imageID },
updateCommande,
function(err){
if(!err){
Like.findOne({imageID : imageID}, function(err,like){
image.likeCount = like.userIDs.length
image.save(function(err){
if(!err){
return res.send({
status: {
error: 0,
message: "Successful"
}
})
}
})
})
}
}
);

double upsert in Node.js and mongoose

var urlSchema = new Schema ( {
url : String,
visitor : [{name: String,date: Date}],
counter : Number
});
var url = mongoose.model('url',urlSchema);
var domain = blah blah;
var conditions = { url: domain };
var update = { $inc : {counter:1},
$push : { visitor: [{
name: data.username,
date: new Date()
}]
}
};
var options = {upsert: true};
url.update(conditions,update,options,function(err){
if(err){
console.log(err);
}else{
console.log('A domain successfully added to DB');
}
Currently I am using the schema and code above to make an access counter for each page.
It upserts url documents which is counting total access and holding access user info.
so far so good It's working properly.
now I want to add "counter : Number" in visitor array and when the event occurs, if the user is already in visitor array,I want to update that instead of pushing new one.
But I have no idea how to make the 'double upsert' command.
is there anyway to do that?
It may be a bit difficult even impossible perform a query that satisfy your condition. I have reproduced your scenario with following query
url.findOne({'url': 'search.php', 'visitor.name': "JohnDoe"},
function (err, visitor) {
if (visitor) {
url.update(
{
'url': 'search.php', 'visitor.name': "JohnDoe"
},
{
$inc: {'visitor.$.counter': 1, 'counter': 1}
},
function(err, result) {
if (err) {
console.log("Error occured")
} else {
console.log("Success");
}
});
} else {
var conditions = { url: 'search.php' };
var update = { $inc : {counter:1},
$push : { visitor: [{
name: data.username,
date: new Date(),
counter: 0
}]
}
};
var options = {upsert: true};
url.update(conditions,update,options,function(err){
if(err){
console.log(err);
}else{
console.log('A domain successfully added to DB');
}
});
}
}
);
Simple, insert if not exists with counter = 0, update if exists with incrementing counter by 1

Categories