I am using a wrapper called mongoskin to access mongoDB. mongoskin is a simple wrapper around mongoDB javascript api.
But when I write to mongoDB, sometimes _id is converted to ObjectID, sometime is it not. The different behavior causes many problem when I have to compare _id. For example:
The following documents in company collection, "creator" is not converted to ObjectID, but item in "clients" is converted to ObjectID automatically.
> db.company.find()
{ "_id" : ObjectId("53d4b452f5b25900005cb998"), "name" : "Default Company Co.", "clients" : [ ObjectId("53d4b452f5b25900005cb999"), ObjectId("53d4b452f5b25900005cb99a") ] }
{ "_id" : ObjectId("53d4b452f5b25900005cb999"), "name" : "client company for 777 - updated", "creator" : "53d4b452f5b25900005cb998", "ssn" : "12-123-1234" }
This is the nodejs code I used to assign _id for "creator"
clientCompany.creator = req.session.user.company_id;
This is the nodejs code I used to assign _id for "clients"
var updateObj = {$addToSet: {clients:resultClient._id} };
// update creator company.clients
creatorCompany.update(updateObj, function(err, result) { ...}
When I console.log "req.session.user.company_id" and "resultClient._id", they both looks like a string type. How come one end up as ObjectID in MongoDB? If there is an auto conversion, how do I make this behavior consistent?
Thanks!
I'm guessing resultClient is the result of a query and req.session.user.company_id a string from your web application? In that case you need to create an ObjectId from the string:
clientCompany.creator = mongoskin.ObjectID(req.session.user.company_id);
Related
Confused with the principalId in Rolemapping.
How to save it in the mongoDb . string or ObjectId.
Which is the correct method for saving it ?
{
"_id" : ObjectId("5d65f6efed4198ce6bc70d58"),
"principalType" : "USER",
"principalId" : ObjectId("5d65f6e9ed4198ce6bc70d57"),
"roleId" : ObjectId("5c74dbc3fe56e53b13b04fd7")
}
OR
{
"_id" : ObjectId("5d65f6efed4198ce6bc70d58"),
"principalType" : "USER",
"principalId" :"5d65f6e9ed4198ce6bc70d57",
"roleId" : ObjectId("5c74dbc3fe56e53b13b04fd7")
}
The correct method to save it is with ObjectId. As the table it is referencing will be having _id that is always a ObjectId default.
ObjectId, Number, String, and Buffer are valid for use as references. However, you should use ObjectId unless you are an advanced user and have a good reason for doing so.
Also if you want to populate this field(principalId), it also becomes easy if you have saved it with ObjectId.
var schema = new Schema({
_id: Schema.ObjectId,
email: {type: String, required: true}
});
Previously email field was unique (with unique constraint)
Now I removed unique constraint, then also it's giving unique validation error. I have restarted mongo then also it's throwing error.
Any Idea?
When you remove the unique constraint in the schema definition, you were supposed to manually remove it from the database as well. You can do this either in mongo shell by using the dropIndex() method or in your application using the native node.js driver's dropIndex() method of the collection.
You may need to confirm this first by checking the indexes currently in the database; you will most probably find the email unique index created when you populated the collection after defining the schema in Mongoose.
You can issue the command in mongo shell, supposing you have a collection named users in your database named test:
> db.users.getIndexes()
which will show the current indexes, you may see in your console an array like the following:
[
{
"v" : 1,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "test.users"
},
{
"v" : 1,
"unique" : true,
"key" : {
"email" : 1
},
"name" : "email_1",
"ns" : "test.users",
"background" : true,
"safe" : null
}
]
For a solution in your application code, supposing you have a Mongoose model called User that has the defined schema above, you can call the getIndexes() native node.js driver's collection method:
User.collection.getIndexes(function (err, results) {
// Handle errors
});
In mongo shell, you can then go ahead and remove the email index with the dropIndex() method :
> db.users.dropIndex("email_1")
In your application code, you can also issue the command via the Mongoose model for the collection, and call the native node.js driver's dropIndex() method of the collection:
User.collection.dropIndex("email_1", function (err, results) {
// Handle errors
});
You can also follow the below steps.
Delete users collection from database.
Save user model(Schema) file and test.
I want to create a PATCH method for my API but there is something I don't understand. Imagine I have the following document in my MongoDB database:
{
_id : ObjectId(1234...),
name : "bob",
age : 30
}
Now I would like to update this document but I don't know what keys my API will receive. So imagine I make a request in order to change the age but also add a last_name.
The request result would be like this:
{
_id : ObjectId(1234...),
name : "bob",
last_name : "smith",
age : 44
}
The main problem here is that I don't know the arguments I will receive.
My goal is to update the values of the existing keys and add the keys that are not in the document.
Any idea?
Thanks
You want to use the $set operator.
What this does is only updates the keys that are sent in the update query. Without $set, it will overwrite the whole object, which is obviously not what you want.
app.patch('/user/:id', function (req, res) {
var updateObject = req.body; // {last_name : "smith", age: 44}
var id = req.params.id;
db.users.update({_id : ObjectId(id)}, {$set: updateObject});
});
I'm assuming a couple things here:
You are using express.
You are using either the mongodb driver or mongojs npm module
I'm using sails-mongo in my project and i need to execute one query in an embedded collection.
My data are something like the following:
{
"_id" : ObjectId("53906c6254f36df504e99b8f"),
"title" : "my post"
"comments" : [
{
"author" : "foo",
"comment" : "foo comment"
},
{
"author" : "bar",
"comment" : "bar comment"
}
],
"createdAt" : ISODate("2014-06-05T13:10:58.365Z"),
"updatedAt" : ISODate("2014-06-05T13:10:58.365Z")
}
for example, i need to extract the comments of author foo.
Apparently sails does not support this feature yet, so i was considering using the object db of mongodb-native to make this kind of query.
As sails-mongo uses mongodb-native, can i have access to db object in my sails project? Or i will need build a new connection using mongodb-native?
If anyone has a better idea I'd be grateful. Thanks
If all you need to do is access the embedded comments, Waterline should work fine. Just do a normal find or findOne, and the comments should be accessible on the returned objects.
If you need to query the comments, e.g. to find Posts with comments by a certain author, you can access the underlying mongodb-native collection using the .native() method of your Sails model class:
Post.native(function(err, collection) {
if (err) {
// handle error getting mongo collection
}
collection.find({'comments.author':'foo'}).toArray(function(err, results) {
// Do something with results
});
});
I'm still learning Mongodb, Nodejs, and Mongoose, so please excuse my ignorance if this question lacks understanding.
I find it somewhat redundant that each Mongodb collection have to be dissected in Mongoose. Specifically, all the fields of each Mongodb collection and their types need to be stated in Mongoose's schema.
So if I have a collection that contains documents sharing the same fields, such as:
> db.people.find()
{ "_id" : ObjectId("1111"), "name" : "Alice", "age": 30 }
{ "_id" : ObjectId("2222"), "name" : "Bob", "age": 25 }
{ "_id" : ObjectId("3333"), "name" : "Charlie", "age": 40 }
The way that Mongoose+Nodejs connect to this Mongodb
var mongoose = require('mongoose');
var personSchema = new mongoose.Schema({
name : String,
age : Number
});
mongoose.model("Person", personSchema, 'people');
where the last line contains the collection name as the 3rd parameter (explained here).
Is it possible to have Mongoose automatically extract the schema somehow from a Mongodb collection for a collection that contains documents of identical fields (i.e. they would have the same schema)? So that we don't have to define the schema in Mongoose.
Mongoose does not currently have a way of automatically building a Schema and Model given an example document.
While a simple document to Schema tool could be written and it would handle some cases reasonably well, depending on the nature of the collections and documents in your database, it wouldn't accurately reflect various aspects of the data model.
For example, if you had two collections that were related:
var personSchema = Schema({
_id : Number,
name : String,
age : Number,
stories : [{ type: Schema.Types.ObjectId, ref: 'Story' }]
});
and
var storySchema = Schema({
title : String
author : String
});
As you can see the stories field is an array of ObjectIds that are associated with the story collection. When stored in the MongoDB collection, it would be something like:
{
"_id" : ObjectId("52a1d3601d02442354276cfd"),
"name" : "Carl",
"age" : 27,
"stories" : [
ObjectId("52a1d33b1d02442354276cfc")
]
}
And stories:
{
"_id" : ObjectId("52a1d33b1d02442354276cfc"),
"title" : "Alice in Wonderland",
"author" : "Lewis Carroll"
}
As you can see, the stories array contains only an ObjectId without storing what it maps to (a document in the stories collection). One functionality of Mongoose that's lost without this connection being established in the schema is populate (reference).
Maybe more importantly, part of the benefit of using Mongoose is to have a declared schema. While it may be "NoSQL" and MongoDB allows documents to be schema-less, many of the drivers in fact encourage developers to have a schema as it helps enforce a consistent document structure in a collection. If you're doing "production" development, having a declared rathered than inferred schema just seems prudent to me. While you can use a design document, having a rigid Schema defined in source code makes it not only the design, but also helps to enforce the Schema from being inadvertently changed.
It's quite easy to declare a Schema in Mongoose and it only needs to be done once per application instance.
You can of course use the underlying driver for MongoDB on NodeJS which doesn't have schema support at all.