I'm using the Node MongoDB driver to collect analytics for my website and send them to MongoLab. How does one insert the current datetime into a document so it can later be used to do aggregation in Mongo?
To be clear, here is the code:
var query = {};
query['date_time'] = new Date();
Db.connect(mongoUri, function (err, db) {
if (!err) {
db.collection(analyticsCollection, function (err, coll) {
if (!err) {
coll.save(query, {safe:true}, function (err, result) {
db.close();
res.send(200,result);
//console.log(result);
});
} else {
res.json(503,{errno:503,msg:'error: collection does not exist.'});
}
});
} else {
res.json(503,{errno:503,msg:'error: database does not exist.'});
}
});
The MongoDB documentation describes how to create a BSON date in the mongo shell, but not in the Node driver and I can't find it in the Node driver docs either.
I found a way to do what I wanted to do. This seems kind of klugey to me, so if anyone can find a better way, please let me know. My solution uses the underscore.js library:
var _ = require('underscore');
vary query = {}
query['foo'] = 'bar'
Db.connect(mongoUri, function (err, db) {
if (!err) {
db.collection(analyticsCollection, function (err, coll) {
if (!err) {
coll.save(_.extend(query,{"datetime":new Date()}), {safe:true}, function (err, result) {
db.close();
res.send(200,result);
//console.log(result);
});
} else {
res.json(503,{errno:503,msg:'error: collection does not exist.'});
}
});
} else {
res.json(503,{errno:503,msg:'error: database does not exist.'});
}
});
Now I can do the aggregation (without needing to use the $project operator):
> db.analytics.aggregate([{$group:{_id:{day:{$dayOfMonth:"$datetime"}}}}])
{ "result" : [ { "_id" : { "day" : 15 } } ], "ok" : 1 }
Hope this helps someone.
Related
Am using Nodejs and MongoDB and I am new to nodejs. I need to know how to get data from one collection and append some additional data and insert into another collection.
db.collection('collection1').find({ "Id" : 12345 }).toArray(function(err, result){
db.collection('collection2', function(err, collection){
collection.insert({
//some data
})
})
})
When I try this code its not working its giving me error insert is not defined.
thanks,
John.
db.collection('collection1').find({ "Id" : 12345 }).toArray(function(err, result){
//do the modification here
db.collection('collection2').insert(modifiedResult, function(err, result){
if(err) {
//log error
}else{
//log result
}
})
})
One more thing, If the result array length is more that one and you want to insert then separately then use promise
db.collection('collection1').find({ "Id" : 12345 }).toArray(function(err, result){
//do the modification here
Promise.all(modifiedResult.map((eachModifiedResult)=>{
return db.collection('collection2').insert(eachModifiedResult);
}).then((result)=>{
//result of the insert
}).catch((err){
//err if any happen
});
})
But if you have a very large doc then do it as Neil Said. Read the collection one by one using cursor and modify them and insert them to other db.
You can use callback library like async or Promises Q
Promise
var collectionData = null;
var modifiedResult = null;
// here i am using async library to avoid callbackHell
async.series([
// for get data from collection 1.
function(cb) {
var criteria = {
"Id": 12345
}
db.collection('collection1').find(criteria).toArray(function(dbErr, dbResult) {
if (err) {
cb(dbErr)
} else {
collectionData = dbResult;
cb()
}
})
},
// Append Data in collectionData
function(cb) {
// do you work here to append data in collectionData
modifiedResult = extendedData; // this is just an example you need to work on it
cb();
},
// Update collection 2 here
function(cb) {
db.collection('collection2').insert(modifiedResult, function(err, result) {
if (err) {
cb(dbErr)
} else {
collectionData = dbResult;
cb()
}
});
}
]);
I have a situation where I have to gather data from three different collections and bundle it together ( there are no joins to be done here) and send it to the client.
Although I have what I think is an elegant solution, I want to ask the community whether there is a cleaner way of performing this operation ?
I am using mongoose as a data modeling layer:
async.parallel([
function(callback) {
ForecastModel.find({facebookId: req.query.playerId}, function(err, result) {
callback(err, result);
});
},
function(callback) {
ScoreModel.find({facebookId: req.query.playerId}, function(err, result) {
callback(err, result);
});
},
function(callback) {
FollowModel.findOne({facebookId: req.query.playerId}, function(err, result) {
callback(err, result);
});
}
],
function(err, results) {
var playerInfo = {};
playerInfo.forecasts = results[0];
playerInfo.score = results[1][0];
playerInfo.followModel = results[2];
res.send(playerInfo);
});
AAAModel.find({'category' : category})
.skip(100)
.sort({date: 'desc'})
.exec(function(err, result) {
if (err) {
next(err);
}
if (result) {
result.remove();
}
});
the above doesn't work.
I would like to remove the 100 Items or more of the search results, what should I do?
You could try one of this approach:
Model.findOne({_id: 'specific_id'}, (err, doc) => {
doc.remove((err) => {
if (err) // handle err
});
// or simply use
doc.remove();
});
or
Model.findOne({_id: 'specific_id'}).remove((err, doc) => {
});
or
Model.remove({_id: 'specific_id'}, (err, doc) => {
});
Use this query
AAAModel.find(
{'category' : category},
{ skip: 100,sort:{date: -1}},
function(err, results) {
if (err) {
next(err);
}
if (result) {
result.remove();
}
});
I've got the same problem.
In fact in latest mongoose query has remove method. So, it theory it could work like this:
AAAModel.find({'category' : category})
.skip(100)
.sort({date: -1})
.remove(function(err, result) {
if (err) {
next(err);
}
if (result) {
console.log("Number of deleted records:" + result);
}
});
But in my case this code removed all records
So, the possible solution is
AAAModel.find({'category' : category})
.select("_id")
.skip(100)
.sort({date: -1})
.exec(function(err, idObjLst) {
if (err) {
return next(err);
}
var ids = idObjLst.map(function(idObj) { return idObj._id; });
if (ids && ids.length > 0) {
AAAModel.remove({_id: {$in: ids}}).exec(function(err, result) {
console.log("Removed " + result + " elements");
});
});
Could be quite expensive though.
As we know, the parameter results is an array of documents in your find callback, not a single document. so you can iterate it and remove item one by one, despite this is not best way to remove documents for performance.
Actually, mongoose Mode.remove can be used to remove documents, but the query condition can not skip and sort until now.
i am inserting data into mongodb using mongodb driver in nodejs.
var mongodb = require('mongodb');
var insert = function(uri, collectionName, data, next) {
mongodb.MongoClient.connect(uri, function(err, driverDb) {
if(err) {
next(err);
} else {
driverDb.collection(collectionName).insert(data,function(err,result) {
if(err) {
next(err);
} else {
driverDb.close(function (err) {
if(err) {
next(err);
} else {
next(null,result);
}
});
}
});
}
});
};
insert('mongodb://localhost/mean-test','testcol',{
a : 'Apple',
b : [ { ba: 'Boy' }, {bb : 'Bird'} ]
}, function(err,models) {
console.log(models);
});
The above result into following:
[{a:'Apple', b : [[Object]] }]
How do i achieve this :
[{_id:ObjectId("someid"), a:'Apple', b : [{_id:ObjectId("someid"), ba: 'Boy' }, {_id:ObjectId("someid"), bb : 'Bird'}] }]
Please note i do not want to use any other npm module except of mongodb.
also i want to insert in one db query.
Your objects are inserting correctly, it's just that console.log only shows two levels of object detail by default. To show all object levels you need to call util.inspect directly so you can control that:
console.log(util.inspect(models, {depth: null}));
I have some collections shown like below which is holding relationships, relation between testMaster and testDoc is holding inside the testDocMaster
For eg:
testMaster {
_id: "Schema.Objectid",
name: "String" //master name
}
testDoc {
_id : Schema.ObjectId,
name: "String", //doc name
other datas
}
testDocMaster {
masterId: "_id of the testMaster table",
docId : "_id of the above testDoc"
}
For each master entry, we are expecting many relations,
what would be the best way to fetch the data from the testDoc table, if I have the masterId.
I got it working using this:
// GLOBAL ARRAYS FOR STORING COLLECTION DATA
var collectionOne = [];
var collectionTwo = [];
app.get('/', function(req, res){
MongoClient.connect("mongodb://localhost:27017/michael", function(err, db) {
if(!err) {
console.log("We are connected");
}
db.collection("collectionOne", function(err, collection) {
collection.find().sort({order_num: 1}).toArray(function(err, result) {
if (err) {
throw err;
} else {
for (i=0; i<result.length; i++) {
collectionOne[i] = result[i];
}
}
});
db.collection("collectionTwo", function(err, collection) {
collection.find().sort({order_num: 1}).toArray(function(err, result) {
if (err) {
throw err;
} else {
for (i=0; i<result.length; i++) {
collectionTwo[i] = result[i];
}
}
});
});
// Thank you aesede!
res.render('index.html', {
collectionOne: collectionOne,
collectionTwo: collectionTwo
});
});
});
});
Now, for some reason when Node restarts, and I hit refresh, it doesn't render HTML into the front-end. However, any subsequent refresh renders the page correctly.
Assuming your testDocMaster schema uses ObjectId types that ref the other two collections you can use Mongoose's query population support to help with this:
TestDocMaster.findOne({ masterId: masterId})
.populate('docId')
.exec(function(err, testDocMaster) {
// testDocMaster.docId is populated with the full testDoc for the
// matching _id
});