How to count aggregate query? - node.js

I'm building pagination with mongoose/nodejs application and have the following code:
var Query = Model.find(
"location": {
"$geoWithin": {
"$box": [
[165.8694369, -52.61941849999999],
[175.831536, -29.2313419]
]
}
}
});
// Get count of documents
return Query.count(function (err, totalCount) {
if (err) throw err;
// Get paginated list
return Query.
find().
skip(skip).
limit(limit).
exec(function (err, results) {
if (err) throw err;
// return result
});
In the preceding code I get totalCount to build pagination on client-side and it works fine. But now I need to use aggregate instead find and trying the following:
// Construct pipeline
var pipeline = [{
"$geoNear": {
"near": [165.8694369, -52.61941849999999],
"distanceField": "distance"
}
}];
var Query = adModel.aggregate(pipeline);
// Get count of documents
return Query.count(function (err, totalCount) {
if (err) throw err;
But unfortunately I get the error count() method does not exists. How could I total count of documents with aggregation framework?

The problem is that Model.aggregate doesn't return a Query object that's why the count method does not exists.
Anyway since it returns a promise you can count your docs like this:
adModel.aggregate(pipeline).then(function (docs) {
console.log(docs.length);
});
and if you don't like promises you can still pass a callback:
adModel.aggregate(pipeline, function (err, docs) {
console.log(docs.length);
});

Related

MongoDB: query greater than value of x by a specfic value

I have a MongoDB database with documents representing locations on a map, the document structure is below.
I'am trying to query for documents with sw_x and sw_y value that is 1000 more or 1000 less than the value of the user location which i get from another post request.
This is my get request:
router.get('/getdata', (req, res) =>{
mongoose.connect(url, function(err, db) {
if (err) throw err;
db.collection("mArGo").find({}).toArray(function(err, result) {
if (err) throw err;
console.log(result);
db.close();
});
})
})
Currently this returns all documents in the database, i just need to figure out how to filter them.
So in other words i need my query to return docs with sw_x, sw_y values that are greater than or less than the user location value by 1000
DB document example:
{
_id: new ObjectId("6172a1dcb5ce25759cd9506b"),
epsg: 25832,
filename: 'dom_657000_5354000_500.sfb',
offset_x: -650000,
offset_y: -5360000,
size_x: 500,
size_y: 500,
x_sw: 657000,
y_sw: 5354000
}
In the code, you can calculate min, max of x_sw and y_sw and pass it to query:
db.collection.find({
x_sw: { $gt: 656000, $lt: 658000 },
y_sw: { $gt: 5353000, $lt: 5355000 }
})

How to skip the 50 records and after that find the matched records in mongodb by using findOne query in node.js

dbo.collection('Gps').findOne({$skip: 50}, { captureDateTime :a5},function (err, result) {
if (result) {
dbo.collection("OBD").insertOne({ sensortype: 'OBD', captureDateTime: result.captureDateTime, vehiculeData: b5 }, function (err, result) {
if (err) throw err;
else
console.log('OBD matched with GPS');
})
}
});
Its not getting proper result. I want to skip the 50 records and then from remaining records I want matched records based on capturedatetime and push it in OBD collection.
I also tried for
dbo.collection('Gps').aggregate([
{$skip : 50},
{ $match : { captureDateTime : a5 } }
]).toArray( function (err, result) {
if (result) {
dbo.collection("OBD").insertOne({ sensortype: 'OBD', captureDateTime: result.captureDateTime, vehiculeData: b5 }, function (err, result) {
if (err) throw err;
else
console.log('OBD matched with GPS');
})
}
});
Might be this can solve your problem link: https://www.w3resource.com/mongodb/mongodb-skip-limit.php
dbo.collection('Gps').findOne().skip(50)
findOne() does not support skip(), since a document is retrieved rather than a cursor. You might use the following method instead :
db.getCollection('Gps').find({captureDateTime :"a5"}).skip(50).limit(1)

Add new property to a document in DocumentDB with nodejs

I have a JSON document in DocumentDB.
I wish to add new data to a given document.
For example.
Current document:
{
"User": "ABC",
"UserID": "123"
}
New document
{
"User": "ABC",
"Height":"1.60",
"UserID": "123"
}
I have tried solutions such as mentioned here:
Add new properties to DocumentDB Document in Stored procedure
But I get "getContext is not defined".
I believe the issue is that I am unsure of how to call a document via a function.
I would like:
var documentURL = "dbs/'dbname'/colls/'collsname'/docs/'docsname'"
editDocument(documentURL)
function editDocument(document) {
var collection = getContext().getCollection();
var response = getContext().getResponse();
document.Height = "1.60";
collection.createDocument(collection.getSelfLink(), document, function(err, result) {
if(err) throw err;
// Return the resulting document back as the response.
response.setBody(result);
});
}
Should I use client.replaceDocument instead, or maybe there is a better way to do this.
The issue may be that the function is plainly trying to use the text location "dbs/colls/docs" in the function rather than the document itself.
Thanks for any help in advance!
Yes, you need to use replaceDocument instead.
var documentURL = "dbs/'dbname'/colls/'collsname'/docs/'docid'"
client.readDocument(documentURL, (err, doc) => {
if(err) return console.log(err);
doc.Height = "1.60";
client.replaceDocument(documentUrl, doc, (err, result) => {
if(err) return console.log(err);
console.log('replaced document');
});
});

MongoDB Query Optimize Search Text

I have an application developed in NodeJS, which works as a REST API and consumes data from MongoDB
In MongoDB I have a collection called 'ftp' with more than 10 million documents with the following structure
{
"_id" : ObjectId("59e7c66911506bd1725cf145"),
"ip" : "72.32.177.76",
"timestamp" : "2017-10-16T02:30:26-04:00",
"data" : {
"banner" : "220-FileZilla Server version 0.9.41 beta\r\n"
}
}
The "data.banner" field is a hased index
From NoodeJs I make an aggregate query that filters a string of text using a regular expression, groups and counts the results.
function getData(timeInit, table, textSearch, res) {
MongoClient.connect(url, function (err, db) {
if (err) throw err;
db.collection(table).aggregate([
{
$match: { 'data.banner': $regex:textSearch}
}, {
$group: {
_id: '$data.banner',
num: { $sum: 1 },
}
},
{
$sort: {
num: -1
}
},{
$limit:5
}
], {
allowDiskUse: true
}
).toArray(function (err, result) {
if (err) throw err;
var timeFinal = new Date();
var data = {
result: result,
timeLapse: (timeFinal - timeInit) / 1000,
numResult: result.length
};
res.send(data);
db.close();
});
});
};
The query with regular expression takes about 8 seconds to return results, an excessive time in my opinion, since the regular expressions are not optimal.
My question is how should I make the filter to search for documents that contain text in an optimal way reducing the response time.
If someone knows how to optimize this type of query I would appreciate it a lot.

How to check if Mongo's $addToSet was a duplicate or not

I am using Mongoskin + NodeJS to add new keywords to MongoDB. I want to notify the user that the entry was a duplicate but not sure how to do this.
/*
* POST to addkeyword.
*/
router.post('/addkeyword', function(req, res) {
var db = req.db;
db.collection('users').update({email:"useremail#gmail.com"}, {'$addToSet': req.body }, function(err, result) {
if (err) throw err;
if (!err) console.log('addToSet Keyword.' );
});
});
The result does not seem to be of any use since it doesn't state if the keyword was added or not.
At least in the shell you can differentiate if the document was modified or not (see nModified).
> db.test4.update({_id:2}, {$addToSet: {tags: "xyz" }})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.test4.update({_id:2}, {$addToSet: {tags: "xyz" }})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 0 })
Update for Node
When you use collection.update(criteria, update[[, options], callback]); you can retrieve the count of records that were modified.
From the node docs
callback is the callback to be run after the records are updated. Has
two parameters, the first is an error object (if error occured), the
second is the count of records that were modified.
Another Update
It seems at least in version 1.4.3 the native Mongo Node driver is not behaving as documented. It is possible to work around using the bulk API (introduced in Mongo 2.6):
var col = db.collection('test');
// Initialize the Ordered Batch
var batch = col.initializeOrderedBulkOp();
batch.find({a: 2}).upsert().updateOne({"$addToSet": {"tags": "newTag"}});
// Execute the operations
batch.execute(function(err, result) {
if (err) throw err;
console.log("nUpserted: ", result.nUpserted);
console.log("nInserted: ", result.nInserted);
console.log("nModified: ", result.nModified); // <- will tell if a value was added or not
db.close();
});
You could use db.users.findAndModify({email:"useremail#gmail.com"},[],{'$addToSet': { bodies: req.body }},{'new':false}). Pay attention to new:false switcher, it allows you to get document before update and you could check whether array contained item before update. However, it could be problematic approach if your documents are big, because you analyze it on client side.
P.S. Your original query with $addToSet is wrong: field name is missing.
Edit: I tried to use count returned by update, but it returns 1 for me in all cases. Here is the code I used for test with MongoDB 2.6:
var MongoClient = require('mongodb').MongoClient;
MongoClient.connect('mongodb://localhost:27017/mtest', function(err, db) {
if(err) throw err;
db.collection('test').insert({_id:1,bodies:["test"]},function(err,item){
db.collection('test').update({_id:1},{$addToSet:{bodies:"test"}}, function(err,affected){
if(err) throw err;
console.log(affected); //1 in console
});
});
});
i am update a array from Collection with this JSON:
{
"<arrayname>":"<value>"
}
route.js
routes.post("/api/:id", Controller.addOne);
Controller.js
async addOne(req, res) {
//juryman id to list add
if (Object.keys(req.body).length === 1) {
console.log("Size 1");
}
await Session.findOneAndUpdate(
{ _id: req.params.id },
{ $addToSet: req.body }
)
.then(function(success) {
res.send("Successfully saved.");
})
.catch(function(error) {
res.status(404).send(error);
});
},
I have five arrays in my Collection and this changes the JSON array name-value and updates correctly, the respectively Collection array. This works only for one item.

Resources