Two same query gives me different records in mongo shell and in native node.js driver:
collection.find(query).limit(1).hint(hint).toArray
collection.find(query).limit(1).hint(hint).toArray
I supposed that in native node.js driver hint is ignored, and it was approved:
when I removed hint from query in node.js driver, the result was the same as I got when I used hint in node.js driver:
collection.find(query).limit(1).toArray
So maybe there is special rule to use hint in node.js mongo native driver? How to use it?
There actually isn't a .hint() method implemented in the node driver. In order to do this you supply "options" to the cursor creation in .find():
collection.find({},{ "hint": { "a": -1 }}).limit(1).toArray(function(err,docs) {
Providing that actually matches an index that is specified then you will get the documents returned in the selected index order. Perhaps a longer example:
var async = require("async"),
mongo = require("mongodb"),
MongoClient = mongo.MongoClient;
MongoClient.connect('mongodb://localhost/test',function(err,db) {
async.waterfall(
[
function(callback) {
db.collection('asample',function(err,collection) {
if (err) throw err;
callback(err,collection);
});
},
function(collection,callback) {
collection.remove(function(err,removed) {
if (err) throw err;
callback(err,collection);
});
},
//
function(collection,callback) {
async.eachSeries(
[
{ "a": 1 },
{ "a": 2 }
],
function(item,callback) {
collection.insert(item,function(err,num) {
if (err) throw err;
callback();
});
},
function(err) {
if (err) throw err;
callback(err,collection);
}
);
},
function(collection,callback) {
collection.ensureIndex({ "a": -1 },function(err,index) {
if (err) throw err;
console.log("Index:\n%s", index);
callback(err,collection);
});
},
function(collection,callback) {
collection.find({},{ "hint": { "a": -1 }})
.limit(1).toArray(function(err,docs) {
if (err) throw err;
console.log("Docs:\n%s", JSON.stringify( docs, undefined, 4));
callback();
});
}
],
function(err) {
console.log("done");
db.close();
}
);
});
Where in the reverse index order the value of "2" is returned first.
Really though, "hint" should not need to be applied as long as either your "query" or .sort() specification mention the correct index to use. So that would be the better approach.
Related
I am using Node.js and Mongoose 5+ to dynamically build a query in the database. The variable filterField is the field name and filterValues is an array. So, my code is like this:
if (req.currentUser.activePage) {
queryParam['pageId'] = req.currentUser.activePage;
if (filterField && filterValues)
queryParam[filterField] = { $in: filterValues };
query = Model.find(queryParam);
console.info(queryParam);
}
Model.paginate(query, options, async (err, result) => {
if (err) {
res.status(500).json({ message: err.errmsg });
} else {
res.status(200).json(result.docs);
}
});
The printed queryParam is as follow:
{ pageId: '123', id: { '$in': [ 1, 2 ] } }
If I run this query directly in the Mongo shell it works fine.
However, when I run this query in Mongoose, it does not return anything when the id: {$in .. is present.
What is the error?
I figured out the error, it is caused by the mongoose-paginate plugin. So, if you are using this plugin with Mongoose, be careful with the parameters you pass to the query.
In my case, passing an array as filter with the option $in does not work with mongoose-paginate.
you have passed wrong parameter query to Model.paginate() method ,try this way :
if (req.currentUser.activePage) {
queryParam['pageId'] = req.currentUser.activePage;
if (filterField && filterValues){
queryParam[filterField] = { '$in': filterValues };
}
Model.paginate(queryParam, options, async (err, result) => {
if (err) {
res.status(500).json({ message: err.errmsg });
} else {
res.status(200).json(result.docs);
}
});
}
I'm very new to javascript/node.js and I'm having trouble with the following code. This is the handler for API an call. The 2nd code segment is just like the 1st, except there is an additional database lookup Merchant.findOne(...), and therefor the 'newTransaction.save()' function is nested one level deeper.
Both code segments return the 'output' variable value correctly. However, the second code segment does NOT also properly save the 'newTransaction' to the Mongo database.
I'm pretty sure the issue has to do with how/when the code returning from newTransaction.save(function (err, transaction){..} but I can't seem to get it straightened out.
I have been looking all over the internet trying to understand and fix this, with no success. Any help is appreciated...
Here is the older, simpler code that works as expected:
handler : function(request, reply) {
var output = {
"success": true,
"operations": [],
"epoch": Date.now()
};
Terminal.findById(request.payload.deviceNumber, function (err, terminal) {
if (err) {
return reply(Boom.internal('Error looking up terminal.', err));
}
if (terminal) {
ticket.quote("bitstamp", "USD", 1, function (err, exchangeRate) {
if (err) {
console.error(err);
return reply(Boom.internal('Error obtaining ticket quote.', err));
}
var newTransaction = new Transaction({
terminal: request.payload.deviceNumber,
merchant: terminal.merchant,
ccExchangeRate: exchangeRate.buy,
fiatAmtDue: request.payload.transactionValue,
ccAmtDue: ccAmtDueTruncated
});
newTransaction.save(function (err, transaction){
if (err) {
return reply(Boom.internal('Error creating new transaction.', err));
}
output.operations.push(
{
"control": "KeyPairGenControl",
"rand": cc.pseudoRandomBytes(32).toString('hex'),
"follow": {
"url": "/pos/v1/AddressAndEncKey",
"post": {
"transactionId": transaction.transactionId
}
}
}
);
return reply(output);
});
});
} else {
return reply(Boom.internal('Error looking up terminal.', err));
}
});
}
Here is the new code that does NOT save the newTransaction data into the Mongo DB.
handler : function(request, reply) {
var output = {
"success": true,
"operations": [],
"epoch": Date.now()
};
Terminal.findById(request.payload.deviceNumber, function (err, terminal) {
if (err) {
return reply(Boom.internal('Error looking up terminal.', err));
}
if (terminal) {
Merchant.findOne({merchantId: terminal.merchant}, function(err, merchant) {
if (err) {
console.log('Cannot find merchant');
return reply(output);
}
var processor = merchant.backendPaymentProcessor.name;
var localCurrency = merchant.localFiatCurrency;
//###################
ticket.quote(processor, localCurrency, 1, function (err, exchangeRate) {
if (err) {
console.error(err);
return reply(Boom.internal('Error obtaining ticket quote.', err));
}
var newTransaction = new Transaction({
terminal: request.payload.deviceNumber,
merchant: terminal.merchant,
ccExchangeRate: exchangeRate.buy,
fiatAmtDue: request.payload.transactionValue,
ccAmtDue: ccAmtDueTruncated
});
newTransaction.save(function (err, transaction){
if (err) {
return reply(Boom.internal('Error creating new transaction.', err));
}
output.operations.push(
{
"control": "KeyPairGenControl",
"rand": cc.pseudoRandomBytes(32).toString('hex'),
"follow": {
"url": "/pos/v1/AddressAndEncKey",
"post": {
"transactionId": transaction.transactionId
}
}
}
);
return reply(output);
});
//return reply(output);
});
//###################
});
} else {
return reply(Boom.internal('Error looking up terminal.', err));
}
});
}
I did a diff of your 2 version:
Check 1
ticket.quote
Callback are identical for both version
processor, localCurrency are different
Is exchangeRate pass into callback correct?
Check 2
newTransaction.save
newTransaction and callback for .save are setup identical
Check(console.log()) the values used in setting up new Transaction({...})
Check transaction object received by callback
Check/debug the code of Transaction.save().
I don't think the issue is with the code you posted. Both version reached return reply(output); inside newTransaction.save's callback. Very likely issue is inside Transaction class or Transaction.save() logic.
One scenario I can think of is when a transaction failed:
Transaction object is available (even for failed transaction)
Transaction Class / Transaction.save() does not write to db because transaction failed
Transaction.save() pass transaction object to callback, but NOT setting err, even when it should.
Mongoose having a feature to specify the collection name under the schema, or as the third argument when declaring the model. Otherwise it will use the pluralized version given by the name you map to the model.
Mongoose official doc having following statement:
Mongoose by default produces a collection name by passing the model name to the utils.toCollectionName method. This method pluralizes the name. Set this option if you need a different name for your collection.
schema-mapped:
new Schema({ <key>: <value>},
{ collection : '<collection name>' }); // collection name
model-mapped:
mongoose.model('<Model name>',
new Schema({ <key>: <value>}),
'<collection name>'); // collection name
You may also find same here
My app should update if tmx is newer, if older do nothing and if doesn't exist insert the document.
If the document is inserted, it works perfectly, else it doesn't update properly or says E11000 dup key.
trying to figure out if my callback are wrong or the logic. (I'm new to node.js+mongodb) MongoClient = require('mongodb').MongoClient,
assert = require('assert'),
url = 'mongodb://localhost:27017/pfc';
MongoClient.connect(url, function (err, db) {
run(db);
});
function run(db) {
fs.readFile('log.log', 'utf8', function (err, source) {
if (err) throw err;
var dataFile = JSON.parse(source);
dataFile.forEach(function (item) {
upsert(db, item, function (err, result) {
if (err) console.dir(err);
});
});
})
}
function upsert(db, doc, callback) {
db.collection('flags').findOne({vid: doc.vid}, function (err, item, result) {
if (item.vid != null) {
if (!(item.tmx instanceof Date)) {
item.tmx = new Date(item.tmx)
}
if(!(doc.tmx instanceof Date)){
doc.tmx = new Date(doc.tmx)
}
if (item.tmx < doc.tmx) {
console.dir("Date validation")
db.collection('flags').updateOne({vid: item.vid}, {
$set: {
"tmx": doc.tmx
}
},{upsert:true}, function (err, result) {
callback(err, result);
}
)
callback(err, result);
}
else{
console.dir("older")
callback(err, result);
}
}
else {
db.collection('flags').insertOne(doc, function(err, result) {
callback(err, result);
});
}
})}
Edit:
The documents from the 'log.log' file have this structure:
{
vid:2848
tmx: "2015-07-18T23:56:17.000Z"
}
{
vid: 2848
tmx: 2015-07-19T00:00:17.000Z
}
collection.find({vid: doc.vid},function(err,item){
if(!item) // didnt find in collection, items with vid: 2848
insert doc to collection
else if(item) //found an item with vid:2848
if (item.tmx < doc.tmx)//only update if doc.tmx is newer
update collection with the most recent document
with #Aaron Dufour help I got rid of the callback problem, thanks :)
but now the problem is when I have the collection already populated and go look for newest documents in log.log, it starts from the oldest document till the newest again :(
Your upsert is vulnerable to race conditions, and run calls it many times in parallel, so that is probably the issue. It is not clear exactly what doc will look like, so you might need slightly more complicated logic, but here's a version that uses Mongo's upsert to make things a bit safer:
function upsert(db, doc, callback) {
db.collection('flags').update({vid: doc.vid}, {$set: doc}, {upsert: true}, function(err) {
db.collection('flags').update({vid: doc.vid, tmx: {$lt: doc.tmx}}, {$set: tmx: doc.tmx}, function(err) {
callback();
});
});
}
I am doing an online course about MongoDB which is unfortunately a little out of date. It seems some of the functions have changed (course is using version 1.4 while I am using 3.0.)
Here is the code I am having trouble with, which I have tried to bring up to date with the current version of MongoDB:
app.js
var MongoClient = require('mongodb').MongoClient;
MongoClient.connect('mongodb://localhost:27017/course', function(err, db) {
if (err) throw err;
db.collection['counters'].findAndModify({
query: {
name: 'comments'
},
update: {
$inc: {
counter: 1
}
},
new: true
}, function(err, doc) {
if (err) throw err;
if (!doc) {
console.dir('No counter found for comments.');
} else {
console.dir('Number of comments: ' + doc.counter);
}
return db.close();
});
});
If I run the same findAndModify through the Mongo shell I get the anticipated result (increment the counter and display the new document,) but when I run this with node it has no effect on the database and throws this error:
TypeError: Cannot call method 'findAndModify' of undefined
Any tips?
Please try:
db.counters('counters').findAndModify
instead of:
db.collection['counters'].findAndModify
use this now:
db.collection('counters').findOneAndUpdate(
{name: 'comments'}, //query
{$inc: {counter: 1}}, //update
{ //options
upsert: true, // create the doc when it's not there
returnOriginal:false // return the modified doc *(new is not supported here!)
},
function(err, r){ //callback
if(err) throw err;
console.log('counter: '+r.value.counter);
}
);
Whoops, I just had the wrong kind of brackets. Should have had:
db.collection('counters')
instead of
db.collection['counters']
Almost like T_G said.
From the mongodb docs:
Existing collections can be opened with collection
db.collection([[name[, options]], callback);
If strict mode is off, then a new collection is created if not already
present.
So you need to do this:
db.collection('counters', function(err, collection){
collection.findAndModify({
query: {
name: 'comments'
},
update: {
$inc: {
counter: 1
}
},
new: true
}, function(err, doc) {
if (err) throw err;
if (!doc) {
console.dir('No counter found for comments.');
} else {
console.dir('Number of comments: ' + doc.counter);
}
});
});
i am creating relationship between two nodes that are created within the code but got error, can sombody tell me what should be arguments of fucnction below and what should be its format
node1.createRelationshipTo(node2, "some", {age:"20"}, function(err, relationship1)
{
if (err) {
console.err('Error saving new node to database:', err);
}
else {
relationship1.save(function (err,result)
{
if(err)
{
console.err('Error saving new node to database:', err);
}
});
}
});
No need to save the relationship after creating it. You can use relationship1 within the callback function.
node1.createRelationshipTo(node2, "some", {age:"20"}, function(err, relationship1) {
if (err) {
console.err('Error saving new node to database:', err);
} else {
// Do something with relationship1 here.
});