Is it possible to execute comparison queries $gt, $lt, etc. of a Date against an ObjectId and vice versa? Does the mongodb driver cast this automatically? Does this mongodb server cast this automatically?
Yes and no.
It is possible under the JavaScript based methods to get a date from the ObjectId value in which you can use for comparisons. It also should be possible to construct an ObjectId given a specific date value as well, but not seeing the utility of that though. But all are valid and essentialy by date:
ObjectId("53473d87cb495e216c982929") > ObjectId("53473e57cb495e216c98292a")
ObjectId("53473d87cb495e216c982929").getTimestamp() >
ObjectId("53473e57cb495e216c98292a").getTimestamp()
ObjectId("53473d87cb495e216c982929").getTimestamp() >
ISODate("2014-04-11T00:55:35Z")
So forms such as this will work, even if really not that great a statement:
db.collection.find({
"$where": function() {
return this._id.getTimestamp() > new Date("2014-01-01");
}
}
As for the "creation" of _id's they are either done in the "driver" or explicitly by the user, or if still omitted the server will generate one.
Related
This question already has answers here:
Why can't you modify the data returned by a Mongoose Query (ex: findById)
(3 answers)
Closed 3 years ago.
while development of an API, I often need to set extra properties in the result of mongoDb query results. But I can't do it in a good way. For example
Model
const Cat = mongoose.model('Cat', { name: String,age:Number });
Query
Cat.findOne({age:2}) .then(
cat=>{
cat.breed="puppy";
console.log(cat)
} )
here after I get the result from mongoDb I want to set the property of breed to the result , but I can't do it because the property is not defined in the Schema
So to set an extra property I use a hack
cat = JSON.parse(JSON.stringify(cat));
cat.favFood = "Milk"
I don't think its a good way to code. please give a better way of setting property and explain how the hack is working.
Mongoose can actually do the conversion toObject for you with the .lean() option. This is preferred over manual conversion after the query (as willis mentioned) because it optimizes the mongoose query by skipping all the conversion of the raw Mongo document coming from the DB to the Mongoose object, leaving the document as a plain Javascript object. So your query will look something similar to this:
Cat.findOne({age:2}).lean().then(
cat=>{
cat.breed="puppy";
console.log(cat)
}
)
The result will be the same except that this will skip the Mongoose document-to-object conversion middleware. However, note that when you use .lean() you lose all the Mongoose document class methods like .save() or .remove(), so if you need to use any of those after the query, you will need to follow willis answer.
Rather than using JSON.parse and JSON.stringify, you can call toObject to convert cat into a regular javascript object.
Mongoose objects have methods like save and set on them that allow you to easily modify and update the corresponding document in the database. Because of that, they try to disallow adding non-schema properties.
Alternatively, if you are trying to save these values you to the database, you may wish to look into the strict option (which is true by default).
I think I'm missing something about the new javascript gremlin client.
I can't find any way to send any kind onf date from my script to the database.
Code example :
import { P } from 'gremlin/lib/process/traversal':
import g from '../path/to/my/gremlin/client';
const myFunction = id => g.V(id).has('some_date', P.gte(new Date())
In this code example I send a javascript date object. I tried a formated string, a timetamp, a stringified timestamp, and one exotical things.
And I always end up wwith an error like this one :
Error: Server error: java.lang.String cannot be cast to java.util.Date (500)
Or this one when I try with a number
Error: Server error: java.lang.Integer cannot be cast to java.util.Date (500)
Is there anything I can do ?
Regards,
F.
I'd suggest storing your Date as a String in your graph using ISO-8601 format. Then you should have no type transformation problems from Javascript as you'll just be sending strings in your Gremlin.
You have to be somewhat aware of the data types you have in your graph versus the ones you have in the target programming language you're using. Unfortunately, there aren't always one-to-one mappings to all the possible types that can be stored in a Java-based graph database (e.g. javax.time.*). For the most portable code and data, try to stick to the primitive types.
I am building a query engine for a database which is pulling data from SQL and other sources. For normal use cases the users can use a web form where the use can specify filtering parameters with select and ranged inputs. But for advanced use cases, I'd like to to specify a filtering equation box where the users could type
AND, OR
Nested parenthesis
variable names
, <, =, != operators
So the filtering equation could look something like:
((age > 50) or (weight > 100)) and diabetes='yes'
Then this input would be parsed, input errors detected (non-existing variable name, etc) and SQL Alchemy queries built based on it.
I saw an earlier post about the similar problem https://stackoverflow.com/a/1395854/315168
There seem to exist several language and mini-language parsers for Python http://navarra.ca/?p=538
However, does there exist any package which would be out of the box solution or near solution for my problem? If not what would be the simplest way to construct such query parser and constructor in Python?
Have a look at https://github.com/dfilatov/jspath
It's similar to xpath, so the syntax isn't as familiar as SQL, but it's powerful over hierarchical data.
I don't know if this is still relevant to you, but here is my answer:
Firstly I have created a class that does exactly what you need. You may find it here:
https://github.com/snow884/filter_expression_parser/
It takes a list of dictionaries as an input + filter query and returns the filtered results. You just have to define the list of fields that are allowed plus functions for checking the format of the constants passed as a part of filter expression.
The filter expression it ingests has to have the following format:
(time > 45.34) OR (((user_id eq 1) OR (date gt '2019-01-04')) AND (username ne 'john.doe'))
or just
username ne 'john123'
Secondly it was foolish of me to even create this code because dataframe.query(...) from pandas already does almost exactly what you need: https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.query.html
Essentially i have a form which takes mm-dd-yy, this value is saved in a database (Value A).
I am using ruby on rails. I am trying to query the database for expired users.
query.push(:expire_date => {:$lt => Time.parse(good_till).utc} )
Problem I am encountering is that the date I pass in the good_till I can convert to UTC using this ruby command, however now i am checking a UTC value to a string.
How do I change my js code in order to save Value A into UTC string to make the two comparable?
I think your :expire_field declaration is incorrect.
Well, it depends on which mongo framework you're using on ruby's app.
Assuming you're using MongoID, you just have to declare your model like this:
class Invoice
include Mongoid::Document
field :expire_date, type: DateTime
end
I'm using what seems to be a common trick for creating a join view:
// a Customer has many Orders; show them together in one view:
function(doc) {
if (doc.Type == "customer") {
emit([doc._id, 0], doc);
} else if (doc.Type == "order") {
emit([doc.customer_id, 1], doc);
}
}
I know I can use the following query to get a single customer and all related Orders:
?startkey=["some_customer_id"]&endkey=["some_customer_id", 2]
But now I've tied my query very closely to my view code. Is there a value I can put where I put my "2" to more clearly say, "I want everything tied to this Customer"? I think I've seen
?startkey=["some_customer_id"]&endkey=["some_customer_id", {}]
But I'm not sure that {} is certain to sort after everything else.
Credit to cmlenz for the join method.
Further clarification from the CouchDB wiki page on collation:
The query startkey=["foo"]&endkey=["foo",{}] will match most array keys with "foo" in the first element, such as ["foo","bar"] and ["foo",["bar","baz"]]. However it will not match ["foo",{"an":"object"}]
So {} is late in the sort order, but definitely not last.
I have two thoughts.
Use timestamps
Instead of using simple 0 and 1 for their collation behavior, use a timestamp that the record was created (assuming they are part of the records) a la [doc._id, doc.created_at]. Then you could query your view with a startkey of some sufficiently early date (epoch would probably work), and an endkey of "now", eg date +%s. That key range should always include everything, and it has the added benefit of collating by date, which is probably what you want anyways.
or, just don't worry about it
You could just index by the customer_id and nothing more. This would have the nice advantage of being able to query using just key=<customer_id>. Sure, the records won't be collated when they come back, but is that an issue for your application? Unless you are expecting tons of records back, it would likely be trivial to simply pluck the customer record out of the list once you have the data retrieved by your application.
For example in ruby:
customer_records = records.delete_if { |record| record.type == "customer" }
Anyways, the timestamps is probably the more attractive answer for your case.
Rather than trying to find the greatest possible value for the second element in your array key, I would suggest instead trying to find the least possible value greater than the first: ?startkey=["some_customer_id"]&endkey=["some_customer_id\u0000"]&inclusive_end=false.
CouchDB is mostly written in Erlang. I don't think there would be an upper limit for a string compound/composite key tuple sizes other than system resources (e.g. a key so long it used all available memory). The limits of CouchDB scalability are unknown according to the CouchDB site. I would guess that you could keep adding fields into a huge composite primary key and the only thing that would stop you is system resources or hard limits such as maximum integer sizes on the target architecture.
Since CouchDB stores everything using JSON, it is probably limited to the largest number values by the ECMAScript standard.All numbers in JavaScript are stored as a floating-point IEEE 754 double. I believe the 64-bit double can represent values from - 5e-324 to +1.7976931348623157e+308.
It seems like it would be nice to have a feature where endKey could be inclusive instead of exclusive.
This should do the trick:
?startkey=["some_customer_id"]&endkey=["some_customer_id", "\uFFFF"]
This should include anything that starts with a character less than \uFFFF (all unicode characters)
http://wiki.apache.org/couchdb/View_collation