Cannot xor mongodb field from nodejs without mongoose - node.js

I'm trying to xor the field status, in a document such as this:
{
"_id" : ObjectId("58c51e1aedb6e4000410ddbf"),
"query" : "developer",
"user_id" : "1413322622039651",
"status" : 1,
"links" : [
"840673302343483394",
"840672745222483968",
"840672580717686785",
"840672427550089216",
"840582170548850688",
"840581988918669312"
],
"links_size" : 6,
"created" : ISODate("2017-03-12T10:08:26.369Z")
}
I'm using this code:
var args = {'_id': new ObjectID(queryId)};
var bit = {$bit: {'status': {xor: 1}}};
db.collection('query').update(args, bit, function(err, result) {});
The query produces no error but the field status is not changed. I think that the problem is that it interprets 1 as a double not as a integer. I tried: parseInt(1) but it also had no effect. I tried to use NumberInt(1) but got the error NumberInt is not defined.
So I can't make it work in my code; however, the equivalent query through the mongo shell works as expected:
db.query.update(
{"_id":ObjectId("58c3b98e458f0700045b1846")},
{"$bit":{"status":{"xor":NumberInt(1)}}}
)
I googled and found that NumberInt is present in the mongoose-int32 package but it requires mongoose. I don't want to add mongoose as a dependency for my project so I'm looking for another solution.

The problem comes from the status field type stored in your document
here it is
{ "status" : 1, ... }
but you should have this:
{ "status" : NumberLong(1), ... }
First, convert all status field to NumberLong using this code (run it directly in the shell)
db.query.find().forEach( function(obj) {
obj.status = new NumberLong(obj.status);
db.query.save(obj);
});
then just update your previous code like this :
const MongoClient = require('mongodb').MongoClient
const ObjectId = require('mongodb').ObjectId
const Long = require('mongodb').Long
MongoClient.connect('mongodb://localhost:27017/database', function (err, db) {
if (err != null) {
console.log(err)
} else {
let args = {'_id': new ObjectId('58c64231b13b6239d9e496da')}
let bit = {$bit: {'status': {xor: Long.fromInt(1)}}}
db.collection('query').update(args, bit, function (err, result) {
if (err != null) {
console.error(err)
}
db.close()
})
}
})
This worked using:
node v7.3.0
npm package mongodb 2.2.24
MongoDB 3.4.1

Related

How to delete an object from an array in mongodb?

MongoDB collection/doc :
{
_id:something,
name:something,
todos: [
{key:1234},
{key:5678}
]
}
I want to delete the object with key:5678 using mongoose query. I did something like this but It's not deleting the object at all and returning the User with unchanged todos array.
Node Route:
router.post('/:action', async (req, res) => {
try {
if (req.params.action == "delete") {
const pullTodo = { $pull: { todos: { key: 5678 } } }
const todo = await User.findOneAndUpdate({ _id:req.body.id} },pullTodo)
if (todo) {
res.json({ msg: "Todo Deleted", data: todo });
}
}
} catch (err) {
console.log(err)
}
})
I have allso tried findByIdAndUpdate(),update() methods but none of them deleting the object from the array. Getting User as a result without deleting the object from the array.
It is working, but you forgot give an configuration to the function call of Model.findByIdAndUpdate..
const todo = await User.findOneAndUpdate({ _id:req.body.id} },pullTodo, {new: true});
// if {new: true} is enabled, then it will give the latest & updated document from the
// result of the query. By default it gives the previous document.
Do some, research first. This isn't a type of question that should be asked. It's already been answered several times in stackoverflow.
Try using Model.findOneAndRemove() instead. It also makes only one call to the database.
Example: User.findOneAndRemove({'todos':{'$elemMatch':{key}});
can you please re-visit your JSON like below and see if this design works for you.
> db.test6.find()
{ "_id" : "mallik", "name" : "mallik-name", "todos1" : { "key1" : [ 1234, 5678 ] } }
> db.test6.update({},{$pull:{"todos1.key1":5678}},{multi:true});
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.test6.find()
{ "_id" : "mallik", "name" : "mallik-name", "todos1" : { "key1" : [ 1234 ] } }
>
I was adding a key property to every "Todo" using "mongoose.Types.ObjectId()" and I was querying with id string like : "5f439....." which was the problem. So I used:
1st Step: MongoId = require('mongodb').ObjectID;
2nd Step: const key = MongoId (**<actual id here>**);

MongoDb Node.js Driver - findOneAndUpdate() behavior without a field given

I noticed a strange behavior with the mongodb node.js driver findOneAndUpate()...
I mistakenly gave it just a objectId string....thinking it would default to searching by _id field of a document.... so, when I used
User.prototype.updatePetArray = function(user, petElement) {
return this.collection.findOneAndUpdate(user,
{ $push: { pets: petElement } },
{ returnOriginal: false,
maxTimeMS: QUERY_TIME});
}
it pulled up and modified this document, which does not have this number at all:
{ "_id" : ObjectId("56d4e2a381c9c28b3056f792"), "username" : "bob123", "location" : "AT", ...}
Why did it modify this document when 56d4d35881c9c28b3056f78a is not in the document?
After I test it following your code with one non-exist ObjectID,
var col = db.collection('users');
col.findOneAndUpdate('56cd129222222', {fname: 'Daved'}, function(err, r) {
if (err)
console.log(err);
else
console.log(r);
db.close();
});
As a result the first document in the collection was changed .
Per this doc
findOneAndUpdate(filter, update, options, callback)
filter: Specify an empty document { } to update the first document returned in the collection.
So I think this non-exist ObjectId is consider to the same behavior with {}
After reviewing the source code of findAndModify, eventually, the
// Execute the command
self.s.db.command(queryObject
is invoked, and the queryObject is
var queryObject = {
'findandmodify': self.s.name
, 'query': query
};
So I test runCommand in mongo shell with non-exist ObjectId as below, as result, the first document is returned.
> db.users.runCommand({findandmodify: 'users', query: '123ddae344', update: true
})
{
"lastErrorObject" : {
"updatedExisting" : true,
"n" : 1
},
"value" : {
"_id" : ObjectId("56c687275d81735019263d1f"),
"fname" : "Daved"
},
"ok" : 1
}
The docs keep saying the filter parameter should be an object.
The wrong behavior is likely to some side effect of mis-interpreting the value, being a string not an object (and maybe a truthy value, non-empty string).

Unable to $pull from array

I have tried a lot of different ways but maybe I dont have the hang of the way mongodb needs me to query it.
this is what the doc looks like.
{
"username" : "amitverma",
"notifications" : {
"notification_add_user" : [
{
"sender" : "a",
"action" : "b",
"type" : "c",
"objectType" : "d",
"objectUrl" : "e"
}
]
},
"_id" : ObjectId("539aa673e97933e7a5000001")
}
I want to remove the object inside "notification_add_user". And these are the different ways I have tried to get it working.
db.notifications.update(
{'username': 'amitverma' },
{ $pull: {
"notifications.notification_add_user":{'sender': "a"}
}}
)
This works in console.
But the code that I have written for it doesnt get the job done.
// notificationtype is 'add_user'
removequery['notifications.notification_' + notificationtype] = { 'sender': 'a' };
co_notifications.update(
{'username': data.username},
{$pull : removequery}, function(err, docs){
console.log('remove notification callback')
console.log(err)
console.log(docs)
})
)
Using the native MongoDB driver, I have used the following query to update from a node console and it works:
>MongoClient = require('mongodb').MongoClient;
>format=require('util').format;
>MongoClient.connect('mongodb://127.0.0.1:27017/test', function(err, db) {
if(err) throw err;
var collection = db.collection('notifications');
collection.count(function(err, count) {console.log(format("count = %s", count));});
collection.update(
{'username': 'amitverma'},
{$pull:{'notifications.notification_add_user':{'sender':'a'}}},{w:1},function(err){
if (err) console.warn(err.message);
else console.log('successfully updated');
})
})
db.notifications.find({'username': 'amitverma' }).forEach( function(result) {
var i;
for(i in result.notifications.notification_add_user) {
var sender = result.notifications.notification_add_user[i]['sender'];
if(sender === 'a') {
delete result.notifications.notification_add_user[i]['sender'];
}
}
db.notifications.save(result);
});
First i will get all the results where the username is equal to
'amitverma'
Then i loop through the notification_add_user array and see if sender is equal to 'a' and delete all the match results
And for last i save the changes

mongoose "_id" vanishing in collection created with map/reduce

I done a very simple map/reduce in mongo console.
var mapState = function () {
emit(this.state, 1);
};
var sumState = function (keyState, valuesCount) {
return Array.sum(valuesCount);
};
db.FooBar.mapReduce(
mapState,
sumState,
{out: "state_counts"}
);
var sc = {};
db.state_counts.find(
{_id: {$exists: true}}).forEach(
function(o){
sc[o._id]=o.value;
}
);
> sc
{
"ak" : 29,
"al" : 5832,
"ar" : 2798,
...
}
> db.state_counts.find().limit(3)
{ "_id" : "ak", "value" : 29 }
{ "_id" : "al", "value" : 5832 }
{ "_id" : "ar", "value" : 2798 }
So far so good. I have the expected state abbreviations and counts in the "sc" object. Oddness occurs when I'm attempting to pull data from state_counts prior to converting it to the equivalent of the "sc" object using mongoose.
#!/usr/bin/env node
mongoose = require("mongoose");
mongoose.connect("mongodb://localhost/thedb");
var schema = new mongoose.Schema({});
schema.collection = 'state_counts';
console.log(schema.collection);
var cur = mongoose.model(schema.collection, schema);
cur.find({}).exec(
function(err, data) {
if (err) {
console.log(err);
mongoose.disconnect();
}
console.log(data);
mongoose.disconnect();
}
);
$ ./test.js
state_counts
[ { value: 29 },
{value: 5832 },
{ value: 2798 },
...
]
This is surprising to me. Why is the "_id" value not showing up in my script when using mongoose?
_id isn't showing up because you haven't defined a schema and mongoose is all about adding schemas to mongodb. So given a completely empty schema, mongoose probably assumes _id will be of type ObjectId (which is conventional for mongodb) and when casting the data in mongodb to that type fails, as it will always do given your data, mongoose omits the value, which makes sense given the majority of mongoose's job is to enforce a consistent schema. This will "fix" it.
var schema = new mongoose.Schema({_id: String, value: Number});

Why does this Node+MongoDB update using addToSet fail to update the array

I can't figure this out, I've tried executing the same query using terminal and it was successful. I should note the same query returns one row effected when using MongoHub but after checking the record there is no change. Below is the mongo setup and the action to update.
var mongo = require('mongodb');
var Server = mongo.Server,
Db = mongo.Db,
BSON = mongo.BSONPure;
var server = new Server('localhost', 27017, {auto_reconnect: true});
db = new Db('help', server, {safe: true});
type = 'issues';
id = 2;
body = { comments: '64' };
db.collection(type, function(err, collection) {
collection.update({id:id}, {$addToSet: body}, {safe:true}, function(err, result) {
if (err) {
console.log('Error updating: ' + err);
res.send({'error':'An error has occurred'});
} else {
console.log('' + result + ' document(s) updated');
res.send(type);
}
});
});
//Mongo Collection Record
{ "_id" : ObjectId( "511c000d994cde0d02adf1ba" ),
"comments" : [
1,
2,
3 ],
"id" : 2,
"text" : "This is another issue test",
"title" : "Another Issue Test" }
Any help is greatly appreciated
turns out I wasn't parsing the variable id as an integer which I was getting from the req.params, I should have included that I was fetching the id from the req.params object.
var id = parseInt(req.params.id);
solved the issue.
Seems like there are a few issues in this part
db.collection(type, function(err, collection) {
collection.update({id:id}, {$addToSet: body}, {safe:true},
I don't see where type variable is defined in the first line. That means that the collection was likely not found. But you don't have any error checking for this issue between the two lines.
In the update statement you should have {_id: ObjectId(id)} where id should 511c000d994cde0d02adf1ba for your example.
Those are the issues which seem obvious right off the bat.

Resources