I'm writing a mongo query to show records based on the current time. However, the query returns 0 records when I try to query against date and time. Below is the query:
let now = momenttz.tz(moment(),tz).toDate();
tmpl.listSelectorFilter('scheduledVisits', {
$gte: now,
$lte: moment.utc(today, 'MM/DD/YYYY').endOf('week').toDate()
});
Note: If I set the time to zero hours, it works.
How do I change this query in order to make it work? Any help is appreciated.
Does the data you're querying against have timestamps or a dateTime object to compare? Essentially you aren't comparing the records to any time, so there is no way for mongo to know what to filter by.
I would suggest you do something like a find instead and compare to dates within the record with the appropriate date field:
example:
db.collection.find({
{ $and: [ { data.date: { $gte: now } }, { data.date: { $lte: endOfWeek } } ] }
})
also keep in mind that in mongo land you can't use functions like you would do with moment, hence why I put "endOfWeek" which would be a variable you set similar to now:
let now = momenttz.tz(moment(),tz).toDate();
let endOfWeek = moment.utc(today, 'MM/DD/YYYY').endOf('week').toDate()
I will start off by saying while I am not new to CouchDB, I am new to querying the views using JavaScript and the web.
I have looked at multiple other questions on here, including CouchDB - Queries with params, couchDB queries, Couchdb query with AND operator, CouchDB Querying Dates, and Basic CouchDB Queries, just to list a few.
While all have good information in them, I haven't found one that has my particular problem in it.
I have a view set up like so:
function (docu) {
if(docu.status && docu.doc && docu.orgId.toString() && !docu.deleted){
switch(docu.status){
case "BASE":
emit(docu.name, docu);
break;
case "AIR":
emit(docu.eta, docu);
break;
case "CHECK":
emit(docu.checkTime, docu);
break;
}
}
}
with all documents having a status, doc, orgId, deleted, name, eta, and checkTime. (I changed doc to docu because of my custom doc key.
I am trying to query and emit based on a set of keys, status, doc, orgId, where orgId is an integer.
My jQuery to do this looks like so:
$.couch.db("myDB").view("designDoc/viewName", {
keys : ["status","doc",orgId],
success: function(data) {
console.log(data);
},
error: function(status) {
console.log(status);
}
});
I receive
{"total_rows":59,"offset":59,"rows":[
]}
Sometimes the offset is 0, sometimes it is 59. I feel I must be doing something wrong for this not to be working correctly.
So for my questions:
I did not mention this, but I had to set docu.orgId.toString() because I guess it parses the URL as a string, is there a way to use this number as a numeric value?
How do I correctly view multiple documents based on multiple keys, i.e. if(key1 && key2) emit(doc.name, doc)
Am I doing something obviously wrong that I lack the knowledge to notice?
Thank you all.
You're so very close. To answer your questions
When you're using docu.orgId.toString() in that if-statement you're basically saying: this value must be truthy. If you didn't convert to string, any number, other than 0, would be true. Since you are converting to a string, any value other than an empty string will be true. Also, since you do not use orgId as the first argument in an emit call, at least not in the example above, you cannot query by it at all.
I'll get to this.
A little.
The thing to remember is emit creates a key-value table (that's really all a view is) that you can use to query. Let's say we have the following documents
{type:'student', dept:'psych', name:'josh'},
{type:'student', dept:'compsci', name:'anish'},
{type:'professor', dept:'compsci', name:'kender'},
{type:'professor', dept:'psych', name:'josh'},
{type:'mascot', name:'owly'}
Now let's say we know that for this one view, we want to query 1) everything but mascots, 2) we want to query by type, dept, and name, all of the available fields in this example. We would write a map function like this:
function(doc) {
if (doc.type === 'mascot') { return; } // don't do anything
// allow for queries by type
emit(doc.type, null); // the use of null is explained below
// allow queries by dept
emit(doc.dept, null);
// allow for queries by name
emit(doc.name, null);
}
Then, we would query like this:
// look for all joshs
$.couch.db("myDB").view("designDoc/viewName", {
keys : ["josh"],
// ...
});
// look for everyone in the psych department
$.couch.db("myDB").view("designDoc/viewName", {
keys : ["psych"],
// ...
});
// look for everyone that's a professor and everyone named josh
$.couch.db("myDB").view("designDoc/viewName", {
keys : ["professor", "josh"],
// ...
});
Notice the last query isn't and in the sense of a logical conjunction, it's in the sense of a union. If you wanted to restrict what was returned to documents that were only professors and also joshs, there are a few options. The most basic would be to concatenate the key when you emit. Like
emit('type-' + doc.type + '_name-' + doc.name, null);
You would then query like this: key : ["type-professor_name-josh"]
It doesn't feel very proper to rely on strings like this, at least it didn't to me when I first started doing it, but it is a quite common method for querying key-value stores. The characters - and _ have no special meaning in this example, I simply use them as delimiters.
Another option would be what you mentioned in your comment, to emit an array like
emit([ doc.type, doc.name ], null);
Then you would query like
key: ["professor", "josh"]
This is perfectly fine, but generally, the use case for emitting arrays as keys, is for aggregating returned rows. For example, you could emit([year, month, day]) and if you had a simple reduce function that basically passed the records through:
function(keys, values, rereduce) {
if (rereduce) {
return [].concat.apply([], values);
} else {
return values;
}
}
You could query with the url parameter group_level set to 1 or 2 and start querying by year and month or just year on the exact same view using arrays as keys. Compared to SQL or Mongo it's mad complicated and convoluted, but hey, it's there.
The use of null in the view is really for resource saving. When you query a view, the rows contain an _id that you can use in a second ajax call to get all the documents from, for example, _all_docs.
I hope that makes sense. If you need any clarification you can use the comments and I'll try my best.
I have dataset as
{"id":1,"Timestamp":"Mon, 11 May 2015 07:57:46 GMT","brand":"a"}
{"id":2,"Timestamp":"Mon, 11 May 2015 08:57:46 GMT","brand":"a"}
The expected result of data is
{"id":1,"Timestamp":ISODate("2015-05-11T07:57:46Z"),"brand":"a"}
{"id":2,"Timestamp":ISODate("2015-05-11T08:57:46Z"),"brand":"b"}
It means I want to revise the Timestamp in each row from string to ISODate
My current code is
db.tmpAll.find().forEach(
function (a) {
a.Timestamp = new Date(a.Timestamp);
db.tmpAll2.insert(a);
}
);
It runs sucessfully, but it will take couple minutes to run the code and it need to create a new collection. Is there any efficient way to do it?
You don't need to create new collection. Use the collection.save method to update your document.
db.tmpAll.find().forEach(function(doc){
doc.Timestamp = new Date(doc.Timestamp);
db.tmpAll.save(doc);
})
I am trying to query a collection in Mongo database, to get all record with Time field in a date range. Time is defined as Date in database.
My environment: Node.js, Express, Jade, javascript.
This is the javascript code:
var query = {};
var timeQuery = {};
timeQuery["$lt"] = new Date().toISOString();
query["Time"] = timeQuery;
console.log(query);
db.model('testruns').find(query).exec(function (err, testruns) {
console.log(testruns.length);
// doing something
});
the result printed to console:
{ Time: { '$lt': '2014-10-30T15:04:39.256Z' } }
0
The query returns 0 results (there should be more)
By the way... Running date queries from RoboMongo returns results, just the wrong ones. for example:
db.testruns.find({Time : {"$gte" : new Date("2014-10-30T15:13:37.199Z")}})
returns all records.
What I tried:
This one, that one, another one, mongoose documentation of course, and many more results from google.
Most of them give the same answer, none of them works for me. HELP!
as far I see you are not including the field to reference in the query, can you try this:
I assume your field name is 'time'
var date = new Date(); //or the date you want to compare
db.model('testruns').find({"Time":{"$lt":date}}).exec(function (err, testruns) {
console.log(testruns.length);
// doing something
});
The problem was related to a schema definition, not directly to this code. The code of the query was correct. a schema definition had this field(Time) as String, which caused MongoDB to try and find a string in a date field...
I'm looking to group a bunch of documents by creation date.
Using the MongoDB Aggregation Framework, is it possible to group documents by the _id's timestamp?
Something of the like
db.sessions.aggregate(
{ $group :
{_id: { $dayOfYear: "$_id.getTimestamp()"},
count: { $sum: 1 }
}
})
Thanks
The function you are referring to here is a JavaScript method implemented as a shell helper for the ObjectId wrapper. Other driver implementations for various languages contain a similar method whose basic function can be seen from the mongo shell as this:
function (){
return new Date(parseInt(this.valueOf().slice(0,8), 16)*1000);
}
But this at least in the shell context is JavaScript and you cannot use JavaScript methods within the aggregation framework, only the implemented operators are allowed. There is presently no "helper" in the aggregation framework methods to extract a "timestamp" from an ObjectId.
As well, the required functions as shown in example above to implement this are lacking at present from the aggregation framework. You cannot possibly "cast" an ObjectId as a string, let alone cast strings as integers or convert from a base type.
For the aggregation framework, the best design approach is to include the required date value in your documents and update accordingly.
If you really wish not to do this and must extract a date from the ObjectId value, then you need to use JavaScript evaluation with mapReduce, or otherwise transfer to client side code:
db.collection.mapReduce(
function() {
// Get time group per day
var id = this._id.getTimestamp()
- ( this._id.getTimestamp() % ( 1000 * 60 * 60 * 24 ) );
delete this._id;
emit( id, this );
},
function(key,values) {
// some reduce operation
},
{ "out": { "inline": 1 } }
)