Mongo DB query in Node.js - node.js

I want to create a query that finds the last insert that I have found.
Here is my dataset in Infos collection.
{
"_id": "5c7114339624d8dd041bae18",
"user_id": "AHK",
"gps": "gps information",
"timestamp": "2010-05-30T20:07:35.000Z",
"__v": 0
},
{
"_id": "5c7114bde3075ae0b38ec0bc",
"user_id": "AHK",
"gps": "gps information2",
"timestamp": "2010-05-30T20:07:35.000Z",
"__v": 0
},
{
"_id": "5c7114c2e3075ae0b38ec0bd",
"user_id": "AHK",
"gps": "gps information3",
"timestamp": "2010-05-30T20:07:35.000Z",
"__v": 0
}
For example, I want to select the data which gps value is "gps information3".
It is the last inserted query In this DB. So I create query like below to select this.
router.get('/infos/gps/:userid/recent',function(req,res){
var temp = Info.find({user_id: req.params.userid}, function(err, info){
if(err) return res.status(500).json({error: err});
if(!info) return res.status(404).json({error: 'user not found in Info collections.'});
}).sort( {"_id": -1} ).findOne(function(err2,info2){
if(err2) return res.status(500).json({error: err2});
if(!info2) return res.status(404).json({error: 'findOne error'});
console.log(info2.user_id +" "+info2.gps+" "+info2.timestamp);
res.json(info2);
});
});
It worked.
But I don't understand the flow. I know that Nodejs is asynnchronous. And it has callback function.
As I guess, First, the find function is called, then sort function is called when the result of find function returned , and finally findOne function is called when the sort function is returned.
But I think that it isn't asynchronous.
Because I thought sort function would proceed before the results of the find function were returned.
Could you tell me what is the answer?
In addition, let me know if there is a way to make this query better.
Last, Can mongodb's _id attribute be the reference point when sorting with time?
I'm a beginner so I have too many questions. I'm sorry.

in mongoose you either:
use a query with a callback, if you pass in a callback function, Mongoose will execute the query asynchronously and pass the results to the callback
Info.find({},callbackFunc);
use a query without a callback and this allows you to chain multiple queries. At the end of the chain you add .exec(callbackFunc) to execute and pass the results to the callback
Info.find({user_id: req.params.userid}).sort({"_id": -1}).findOne().exec(callbackFunc)
the callback functions are something like this:
function callbackFunc (err,docs) {
if (err) {
console.log(err); // do something
}
if (!doc) {
// do something else
}
console.log(doc); //do the main thing
}
Frankly, I have no idea how the code you posted works, but if it does, it's definitely not supported.
https://mongoosejs.com/docs/queries.html
As to why you can sort by id and get it sorted in chronological order, that's because in MongoDB we get a timestamp for free if we define our primary key as an ObjectId. This is because the 12 byte ObjectId type contains a 4 byte time component.
http://www.syntaxsuccess.com/viewarticle/sorting-by-objectid-in-mongodb

Related

get Data from a collection in MongoDB using NodeJS

I am trying to get data from Mongo DB by filtering a nested object.
the collection structure is :
{
"id":"8820624457",
"type":"CreateEvent",
"actor":{
"id":27394937,
"login":"Johnson0608",
"display_login":"Johnson0608",
"gravatar_id":"",
"url":"https://api.github.com/users/Johnson0608",
"avatar_url":"https://avatars.githubusercontent.com/u/27394937?"
},
"repo":{
"id":163744671,
"name":"Johnson0608/test",
"url":"https://api.github.com/repos/Johnson0608/test"
},
"payload":{
"ref":"master",
"ref_type":"branch",
"master_branch":"master",
"description":null,
"pusher_type":"user"
},
"public":true,
"created_at":"2019-01-01T15:00:00Z"
}
I am trying to get data by repo id.
my code is :
collection.find({'repo.id':id}).toArray(function(err, docs) {
console.log(id);
assert.equal(err, null);
console.log("Found the following records");
console.log(docs);
res.status(200).json({docs});
callback(docs);
});
but I am getting empty array, would be grateful is someone can point me to the right direction
MongoDB compares types before values. If your id comes from req.params it's probably passed as string while repo.id seems to be a number. Try to convert your value to number:
const id = +req.params.repoId

Dynamoose query by different attributes (Node.js)

I need to get record (-s) from DynamoDB via Dynamoose by non-key attribute. For example, I need to get all records from the table someModel where the field my_field is equal to 111. I do it by the next way:
const data = await someModel.query("my_field").eq("111").exec();
And this code stops executing! I mean that following code after that is not called.
If I change code to this:
const data = await someModel.query("my_field").eq("111");
my query is working, but data contains:
{
"options": {
"all": {
"delay": 0,
"max": 1
}
},
"query": {
"hashKey": {
"name": "my_field",
"value": "111"
}
},
"filters": {},
"buildState": false,
"validationError": null,
"notState": false,
"success": true
}
I understand that above code is prepared query parameters for query but how can I apply them and execute query to DynamoDB? Of course the query code is placing inside async function - that is why await is written there.
I use also serverless framework for describing DynamoDB schemes. But all models I write via dynamoose.
Where am I mistaking?
As mentioned in the documentation here, Dynamoose query returns the value in the callback and not as a promise. Therefore, your response is actually returned in a callback that should come inside the exec part of your query. async/await is valid for promises and not callbacks.
someModel.query("my_field").eq("111").exec((err, data) => {
// Do whatever you wish to with your data
});

A find() statement with possible null parameters

I'm trying to figure out how Mongoose and MongoDB works... I'm really new to them, and I can't seem to figure how to return values based on a find statement, where some of the given parameters in the query possible are null - is there an attribute I can set for this or something?
To explain it further, I have a web page that has different input fields that are used to search for a company, however they're not all mandatory.
var Company = mongoose.model('Company');
Company.find({companyName: req.query.companyName, position: req.query.position,
areaOfExpertise: req.query.areaOfExpertise, zip: req.query.zip,
country: req.query.country}, function(err, docs) {
res.json(docs);
});
By filling out all the input fields on the webpage I get a result back, but only that specific one which matches. Let's say I only fill out country, it returns nothing because the rest are empty, but I wish to return all rows which are e.g. in Germany. I hope I expressed myself clearly enough.
You need to wrap the queries with the $or logic operator, for example
var Company = mongoose.model('Company');
Company.find(
{
"$or": [
{ "companyName": req.query.companyName },
{ "position": req.query.position },
{ "areaOfExpertise": req.query.areaOfExpertise },
{ "zip": req.query.zip },
{ "country": req.query.country }
]
}, function(err, docs) {
res.json(docs);
}
);
Another approach would be to construct a query that checks for empty parameters, if they are not null then include it as part of the query. For example, you can just use the req.query object as your query assuming the keys are the same as your document's field, as in the following:
/*
the req.query object will only have two parameters/keys e.g.
req.query = {
position: "Developer",
country: "France"
}
*/
var Company = mongoose.model('Company');
Company.find(req.query, function(err, docs) {
if (err) throw err;
res.json(docs);
});
In the above, the req.query object acts as the query and has an implicit logical AND operation since MongoDB provides an implicit AND operation when specifying a comma separated list of expressions. Using an explicit AND with the $and operator is necessary when the same field or operator has to be specified in multiple expressions.
If you are after a query that satisfies both logical AND and OR i.e. return all documents that match the conditions of both clauses for example given a query for position AND country OR any other fields then you may tweak the query to:
var Company = mongoose.model('Company');
Company.find(
{
"$or": [
{ "companyName": req.query.companyName },
{
"position": req.query.position,
"country": req.query.country
},
{ "areaOfExpertise": req.query.areaOfExpertise },
{ "zip": req.query.zip }
]
}, function(err, docs) {
res.json(docs);
}
);
but then again this could be subject to what query parameters need to be joined as mandatory etc.
I simply ended up deleting the parameters in the query in case they were empty. It seems all the text fields in the submit are submitted as "" (empty). Since there are no such values in the database, it would return nothing. So simple it never crossed my mind...
Example:
if (req.query.companyName == "") {
delete req.query.companyName;
}

.findOne not passing results to callback

This must be a stupid question, but I've bashed my head against the wall for long enough.
Short version: I have a query that returns a result as expected in the Mongo console, but returns no results (or errors) when used through the Mongo NodeJS package.
var weatherCacheQuery = {
'location': {
'$near': {
'$geometry': {
type: 'Point',
coordinates: [location.coordinates[0], location.coordinates[1]]
},
'$maxDistance': 50000
}
},
'retrieved': {
'$gte': moment().subtract(2, 'hours').toDate()
}
};
this.db.collection('weather').findOne(
weatherCacheQuery,
function(err, doc) {
console.log(JSON.stringify(err));
console.log(JSON.stringify(doc));
}
});
As you can see, nothing overly complex.
If I dump the query object and paste it into a findOne query in the Mongo console, it returns a single result that looks exactly as it should. In the JS, though, the two console.log()s return null.
Somewhat more weirdly, find() with the same query does return a result, but not one that I can view because JSON.stringify() complains about it being circular.
Can anyone point out the doubtlessly absurd thing I'm doing wrong?
.findOne for the node MongoDB driver takes three arguments, and none of them seem to be optional. Try:
this.db.collection('weather').findOne(
weatherCacheQuery, {},
function(err, doc) {
console.log(JSON.stringify(err));
console.log(JSON.stringify(doc));
}
});
You can also try it with a promise, chain .then to .findOne and pass the callback to that.
The docs also say that .findOne is deprecated and to use.
find().limit(1).next
You can pass the callback to that.

Mongoose find always returning true when it shouldn't

I’m using Mongoose.js to interface with my Mongo database. This function searches through my Location names and should be logging not found to the console instead of found, as I don't have a Location with the name !#£.
Location.find({name: "!#£"}, function(err, obj) {
console.log(obj);
if (!err) {
console.log("found");
} else {
console.log("not found");
}
});
This is what is logging out to my console:
[]
found
The expected behaviour should be for it to log not found to the console. Here's a dump of the Location model data:
[
{
"_id":"5384c421af3de75252522aa2",
"name":"London, UK",
"lat":51.508515,
"lng":-0.12548719999995228,
"__v":0,
"modified":"2014-05-27T16:58:09.546Z",
"search_count":1
},
{
"_id":"5384c766af3de75252522ab4",
"name":"Paris, France",
"lat":48.856614,
"lng":2.3522219000000177,
"__v":0,
"modified":"2014-05-27T17:12:06.990Z",
"search_count":1
},
{
"_id":"53851a213a33fe392b758046",
"name":"Zagreb, Croatia",
"lat":45.8150108,
"lng":15.981919000000062,
"__v":0,
"modified":"2014-05-27T23:05:05.306Z",
"search_count":1
}
]
The callback interface semantics are not what you think.
err means the query failed entirely due to an error like the DB being unreachable. It has no meaning with regard to whether documents matched or not
obj is an array of results, which you should name "locations" IMHO to keep things clear. If no documents match the query, this array will be empty. If some match, they will be in the array.
So there are 3 total states to consider: error, success with no matches, success with some matches.

Resources