I have a web app that posts a JSON request to a Node/Express server, which then inserts a new document into a local MongoDB database using the latest version of the mongodb Node module. When I view the documents using MongoChef, all integers are wrapped with NumberInt(x).
"shirts" : {
"adult-x-large" : NumberInt(2),
"youth-small" : NumberInt(1),
"adult-small" : NumberInt(1),
"adult-medium" : NumberInt(1)
}
I'm sure these wrappers are useful for certain applications, but I really don't want my JSON filled with them. Is there a way to disable this? I'm not sure if this is a MongoDB issue, a MongoChef issue, or something else entirely.
It is just a display part in MongoChef. If you view the data in "TreeView", it should show the type as Int32 with just numeric value.
As long as the datatye is "Int32", it should be correct and as expected.
MongoChef JSON View:-
MongoChef Tree View:-
RoboMongo Json View:-
Related
TLDR
Is there a way to limit queryByExample to a collection in NodeJS?
Problem faced
I have a complex query with some optional fields (i.e. sometimes some search fields will be omitted). So I need to create a query dynamically, e.g. in JSON. QueryByExample seems to be the right tool to use here as it gives me that flexibility to pass a JSON. However my problem is that I would like to limit my search to only one collection or directory.
e.g. I was hoping for something like
searchJSON = {
title: { $word: "test" },
description: { $word: "desc" }
};
//query
db.documents.query(qb.where(
qb.collection("collectionName"),
qb.byExample(searchJSON)
)).result()...
In this case searchJSON could have been built dynamically, for example maybe sometimes title may be omitted from the search.
This doesn't work because the query builder only allows queryByExample to be the only query. But I'd instead like to built a dynamic search query which is limited to a collection or directory.
At present, I think you would have to express the query with QueryBuilder instead of Query By Example using
qb.and([
qb.collection('collectionName'),
qb.word('title', 'test'),
qb.word('description', 'desc')
])
See http://docs.marklogic.com/jsdoc/queryBuilder.html#word
That said, it should be possible for the Node.js API to relax that restriction based on the fixes in MarkLogic 9.0-2
Please file an issue on https://github.com/marklogic/node-client-api
Is there a way to tell the native MongoDB driver for NodeJS to automatically convert the contents of an _id field into an ObjectID?
Say, in this situation:
db.collection("collection").updateOne({_id: data._id}, data)
It's not that data._id = ObjectID(data.id) is hard, but it's another thing to miss each and every time.
There is no way to do that natively. You can make some function for wrapping your mongo queries where you will check params and if it's "_id" parse it to ObjectId.
I'd like to have a flexible schema in Mongo, but would also like to enforce a schema for subsequent updates. Is it possible to store the validation in the document like the following?
I have tried this, but can't seem to convert the string into a Joi object.
{
"_id" : ObjectId("53d5dce1fc87899b2b3c2def"),
"name" : {
"validator" : "Joi.string().alphanum().min(3).max(30).required()",
"value" : "Bob"
},
"email" : {
"validator" : "Joi.string().email()",
"value" : "bob#gmail.com"
}
}
Most of the time, storing executable code in a database is not a good idea. What will you do when you realize a validator function which is already stored in a billion documents needs to be modified? What if someone manages to insert a document with validation code which does more malicious stuff than just validating?
I would really recommend you to determine the type of the document and the appropriate validation routine for each type in node.js.
But when you insist on having executable code for each document in the document itself, you can run that code in node.js using the vm.runInContext(object.validator, object) method. Keep in mind that this requires access to the whole document in node.js, so you can not do partial updates. Also keep in mind that, as I said, it might not be a very good idea.
In the upcoming Mongo 3.2 version they are going to add document validation (slides).
It will work in a different way and looking at your requirements it looks like it is possible to achieve what you want. It is possible to specify the type of the field, check the existence and pass through regex.
Here is a little bit about validation. You can specify validation rules for each collection, using validator option using almost all mongo query operators (except $geoNear, $near, $nearSphere, $text, and $where).
To create a new collection with a validator, use:
db.createCollection("your_coll", {
validator: { `your validation query` }
})
To add a validator to the existing collection, you can add the validator:
db.createCollection("your_coll", {
validator: { `your validation query` }
})
Validation work only on insert/update, so when you create a validator on your old collection, the previous data will not be validated (you can write application level validation for a previous data). You can also specify validationLevel and validationAction to tell what will happen if the document will not pass the validation.
If you try to insert/update the document with something that fails the validation, (and have not specified any strange validationLevel/action) then you will get an error on writeResult (sadly enough the error does not tell you what failed and you get only default validation failed):
WriteResult({
"nInserted" : 0,
"writeError" : {
"code" : 121,
"errmsg" : "Document failed validation"
}
})
Basically the query works in mongo but not in sails controller:
db.membermodel.find({identifier:{$in:["2","3","4"]}); // works
MemberModel.find({
identifier:{$in:["2","3","4"]},
}).then(function(members){
// doesn't work
});
data returned:
{ "_id" : ObjectId("52d1a484f2b5e88cb5d4072c"), "identifier" : "2", "deviceToken" : "token2"}
{ "_id" : ObjectId("52d1a487f2b5e88cb5d4072d"), "identifier" : "3", "deviceToken" : "token3"}
Thanks,
Mars
This isn't the way to do in queries with Waterline. You simply set the attribute you're selecting to the array value:
MemberModel.find({
identifier:["2","3","4"]
}).exec(function(err, members){
...
});
If you really need to use low-level Mongo features, you can get an instance of the native collection with
MemberModel.native(function(err, collection) {
//do native mongo driver stuff with collection
}
Hard to understand how the model is being queried but I suggest you to "spy" what's Mongo getting as the MVC framework query, due to this is not a direct query to Mongo, it's passed through the framework.
I'm quite sure you're still developing so you have access to your mongo instance, restart it using full profile (the trick is everything is slow under 1ms)
mongod --profile=1 --slowms=1 &
Tail the resulting log which normally is in
/var/log/mongodb/mongodb.log
with the command
tail -f /var/log/mongodb/mongodb.log
Send your query again and check what MongoDb is executing.
Each time I have to perform a query involving _id, I have to do new ObjectID( _idAsString) in order for it to work. I realize mongo tests the object, not the value itself, but this is adding a lot of overhead and I may miss converting it in some places.
The _id goes to the client where the ObjectID( string ) is turned to string and when it comes back from the client, I would have to remake it into ObjectID( string ). I will mention that "string" is the actual value generated by mongo, something like 123a1b12dc...
If there is another good/complete library with such a internal functionality, I would love to try it out.
There are some Node.js object mappers which provide this functionality. Take a look at Mongolia.
https://github.com/masylum/mongolia#mappings-and-type-casting