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"
}
})
}
})
})
}
}
);
Related
I created a live pool app where you can create, view and delete questions from the table pools from the rethinkdb database.
The delete is the problem. When I use a DELETE request with POSTMAN, it works, the table is deleted. But when I click on the delete button in Angular, it doesn't do anything. How do I create a DELETE http request ?
This is my delete code that works in the database:
deletePolls(pollData,callback) {
async.waterfall([
function(callback) {
var pollObject = new db();
pollObject.connectToDb(function(err,connection) {
if(err) {
return callback(true,"Error connecting to database");
}
callback(null,connection);
});
},
function(connection,callback) {
//THIS DELETES THE TABLE FROM THE DATABASE
rethinkdb.table('poll').delete().run(connection,function(err,result) {
connection.close();
if(err) {
return callback(true,"Error happens while deleting polls");
}
callback(null,result);
});
}
],function(err,data) {
callback(err === null ? false : true,data);
});
}
This is the button in my index.html, that calls the function delete():
<md-button ng-submit="delete()">Delete the table</md-button>
This is the function that should delete:
$scope.delete = function() {
$http.delete("/polls",data).success(function(response) {
if(response.responseCode === 0) {
console.log("Success");
console.log("IvanUspeh");
$scope.hiddenrows.push(index);
} else {
console.log("error");
}
});
};
Here is the full app.js, the javascript that angular works with:
var app = angular.module('starterApp', ['ngMaterial','ngRoute','ngMessages']);
app.factory('socket',function(){
var socket = io.connect('http://localhost:3000');
return socket;
});
app.config(function($routeProvider){
$routeProvider
.when('/',{
templateUrl: 'home.html'
})
.when('/create',{
templateUrl: 'create.html'
})
.when('/view',{
templateUrl: 'view.html'
})
.when('/delete',{ //IGNORE THIS, THIS JUST OPENS AN EMPTY HTML
templateUrl: 'delete.html'
})
;
});
app.controller('pollingController',function($scope,$mdDialog,$http,socket) {
$scope.pollData = [];
$scope.formData = {};
$scope.voteData = {};
$scope.hiddenrows = [];
getPollData();
function getPollData() {
$http.get("/polls").success(function(response){
$scope.pollData = response.data;
});
}
$scope.submitPoll = function(ev) {
var data = {
"question" : $scope.formData.pollQuestion,
"polls" : [{
"option" : $scope.formData.pollOption1, "vote" : 0
},{
"option" : $scope.formData.pollOption2, "vote" : 0
},{
"option" : $scope.formData.pollOption3, "vote" : 0
}]
};
var message = {"title" : "", "message" : ""};
$http.post('/polls',data).success(function(response) {
if(response.responseCode === 0) {
message.title = "Uspeh !";
message.message = "Anketa je uspešno napravljena.";
data["id"] = response.data.generated_keys[0];
$scope.pollData.push(data);
} else {
message.title = "Greška !";
message.message = "Greška u toku pravljenja ankete.";
}
$mdDialog.show(
$mdDialog.alert()
.parent(angular.element(document.querySelector('#popupContainer')))
.clickOutsideToClose(true)
.title(message.title)
.textContent(message.message)
.ok('Got it!')
.targetEvent(ev)
);
});
}
$scope.updateVote = function(index) {
var data = {
"id" : $scope.pollData[index].id,
"option" : $scope.pollData[index].selected
};
$http.put("/polls",data).success(function(response) {
if(response.responseCode === 0) {
console.log("Success");
$scope.hiddenrows.push(index);
} else {
console.log("error");
}
});
}
$scope.delete = function() {
$http.delete("/polls",data).success(function(response) {
if(response.responseCode === 0) {
console.log("Success");
console.log("IvanUspeh");
$scope.hiddenrows.push(index);
} else {
console.log("error");
}
});
};
socket.on('changeFeed',function(data) {
for(var pollCounter = 0 ;pollCounter < $scope.pollData.length; pollCounter++) {
if($scope.pollData[pollCounter].id === data.id) {
$scope.pollData[pollCounter].polls = data.polls;
$scope.$apply();
}
}
});
});
So, when I push the button with the function delete(), I want it to delete everything in the table like in POSTMAN, like a http request. What am I doing wrong ?
This is not much of a solution , rather a suggestion on how to debug
You are capturing only the success from the http call but not the error . You can write the function like below to more detail on where its failing.
$scope.delete = function() {
console.log("delete function called");
$http.delete("/polls",data).success(function(response) {
if(response.responseCode === 0) {
console.log("Success");
console.log("IvanUspeh");
$scope.hiddenrows.push(index);
} else {
console.log("error");
}
})
.error(function (data, status, header, config) {console.log(status)});
};
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
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();
});
};
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 } } );
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