mongodb - understanding references ids and ObjectId - which format to use? - mongodb

var publisherSchema = Schema({
_id : Number,
name : String,
founded : Number,
books : [{ type: Schema.Types.ObjectId, ref: 'Book' }]
});
var bookSchema = Schema({
_id : Number,
title : String,
author : [{type: String}],
pages: Number,
language: String
});
var Book = mongoose.model('Book', bookSchema);
var Publisher = mongoose.model('Publisher', publisherSchema);
Trying to understand ObjectId: the type for books as listed as Schema.Types.ObjectId. Objectids are generated by Mongodb automatically.
If I add ids to the book array manually, type will be just strings. Do I need to somehow also generate Objectids saved in the books array so when I make a query (findById) I will find it or is it enough if I just add those id's as strings?
I read in another post its better to generate ObjectIds and not just strings to reduce space. Im confused by this as I read that they normally generated by mongodb. If I can (and should) generate them for ids -how to?
When I make a reference
books : [{ type: Schema.Types.ObjectId, ref: 'Book' }]
that is just for the developer to know that the id's are suppose to belong to the books collection, there is no internal linking functionality to the books collection from the publisher collection?!
Thanks!!

Related

ref to filed of collection instead of collection mongodb

I have a schema like this
const Schema1 = new Schema({
field11: String,
field12: [
{ _id: Schema.Types.ObjectId,
title: String
}
]
})
and another schema which has a field to reference to filed of the first collection as below
const Schema2 = new Schema({
field21: String,
field22: [
{_id: {type: Schema.Types.ObjectId},
{ref: 'Schema1.filed12'}
]
})
I need to populate field22 in schema2. How do I need to do it.
The below query doesn't work for me.
Schema2.find(field21).populate('Schema1.field12')
According to the documentation:
The ref option is what tells Mongoose which model to use during population, in our case the Story model. All _ids we store here must be document _ids from the Story model.
You are attempting to store non-id fields as a reference that should point to subdocuments that are nested in an array of your Schema1 model. This simply doesn't work.

Mongoose query document by field value and subdocument field value

I'm using mongoose and trying to get document by specific value of field on it and subdocument field's specific value. I dig a lot but I was unable to find anything matching - I am also new to MongoDb.
So my schema looks like :
messageSchema = Schema candidateId: {type: string},
template: {type: Schema.Types.ObjectId, ref: 'MessageTemplate'},
messageTemplate = Schema name:{type: string}, isActive:{type: boolean}
So I want to get all messages that have certain candidateId and messageTemplate.isActive equal to true.
I couldn't figure out query so I am doing work around like this
Message.find({candidateId: candidateId})
.populate('template')
.then(res => res.fileter(message => message.template.isActive)
It's working but I'm guessing it's possible to create better query, any help will be great.

Is it better to save id of a document in another document as ObjectId or String

Lets take a simple "bad" example : lets assume I have 2 collections 'person' and 'address'. And lets assume in 'address' I want to store '_id' of the person the address is associated with. Is there any benefit to store this "referential key" item as ObjectId vs string in 'address' collection?
I feel like storing them as string should not hurt but I have not worked in mongo for very long and do not know if it will hurt down the road if I follow this pattern.
I read the post here : Store _Id as object or string in MongoDB?
And its said that ObjectId is faster, and I assume its true if you are fetching/updating using the ObjectId in parent collection(for eg. fetching/updating 'person' collection using person._id as ObjectId), but I couldn't find anything that suggests that same could be true if searching by string id representation in other collection(in our example search in address collection by person._id as string)
Your feedback is much appreciated.
Regardless of performance, you should store the "referential key" in the same format as the _id field that you are referring too. That means that if your referred document is:
{ _id: ObjectID("68746287..."), value: 'foo' }
then you'd refer to it as:
{ _id: ObjectID(…parent document id…), subDoc: ObjectID("68746287...")
If the document that you're pointing to has a string as an ID, then it'd look like:
{ _id: "derick-address-1", value: 'foo' }
then you'd refer to it as:
{ _id: ObjectID(…parent document id…), subDoc: "derick-address-1" }
Besides that, because you're talking about persons and addresses, it might make more sense to not have them in two documents altogether, but instead embed the document:
{ _id: ObjectID(…parent document id…),
'name' : 'Derick',
'addresses' : [
{ 'type' : 'Home', 'street' : 'Victoria Road' },
{ 'type' : 'Work', 'street' : 'King William Street' },
]
}
As for use string as id of document, in meteor collection, you could generate the document id either Random.id() as string or Meteor.Collection.ObjectID() as ObjectId.
In this discussion loop, Mongodb string id vs ObjectId, here is one good summary,
ObjectId Pros
it has an embedded timestamp in it.
it's the default Mongo _id type; ubiquitous
interoperability with other apps and drivers
ObjectId Cons
it's an object, and a little more difficult to manipulate in practice.
there will be times when you forget to wrap your string in new ObjectId()
it requires server side object creation to maintain _id uniqueness
- which makes generating them client-side by minimongo problematic
String Pros
developers can create domain specific _id topologies
String Cons
developer has to ensure uniqueness of _ids
findAndModify() and getNextSequence() queries may be invalidated
All those information above is based on the meteor framework. For Mongodb, it is better to use ObjectId, reasons are in the question linked in your question.
Storing it as objectId is benificial. It is faster as ObjectId size is 12 bytes compared to string which takes 24 bytes.
Also, You should try to de-normalize your collections so that you don't need to make 2 collections (Opposite to RDBMS).
Something like this might be better in general:
{ _id : "1",
person : {
Name : "abc",
age: 20
},
address : {
street : "1st main",
city: "Bangalore",
country: "India"
}
}
But again, it depends on your use case. This might be not suitable sometimes.
Hope that helps! :)

DbRef with Mongoose - mongoose-dbref or populate?

I have the following 2 schemas:
Company Event:
var companyEventSchema = new Schema({
name : String,
description
date : Date,
attendees : [ { type : Schema.ObjectId, ref : 'Member' } ],
]});
And Member
var memberSchema = new Schema({
name : String,
emailAddress: String,
password :String,
created: { type: Date, default: Date.now }
});
Is the way i've ref'd Member from companyEventSchema correct?
I'm trying to do something a long the lines of a dbref.
I saw theres a separate project for that though... mongoose-dbref
However, the mongoose docs say the above provides "dbref like functionality"
Which would be more efficient?
You only need to use an actual DBRef (and mongoose-dbref) for the case where a field can contain ObjectIds that reference documents in potentially more than one collection. A DBRef is a tuple of an ObjectId, a collection name, and an optional database name.
Mongoose ref: fields, however, contain just an ObjectId and it's the Mongoose schema that defines what one collection the ObjectIds reference.
So Mongoose ref: fields are more efficient and should always be used unless you need the multi-collection reference support that DBRef provides.

Using a selfdefined ObjectId and avoiding double entries in Mongoose

I am getting JSON objects through an external API in node.js and want to store them in MongoDB. I defined a model like this:
var Product = new Schema({
id: ObjectId,
name: String});
And now I'm trying to store an object:
JSONProduct = { id: 1234, name: 'The Foo Bar' };
product = new Product(JSONProduct);
product.save();
The object is stored fine in the "products" collection, but the id from the JSONProduct is replaced by a MongoDB created value:
{ "id" : ObjectId("119894980274616772006500"), "name" : "The Foo Bar" }
The main reason why I want to use my Product id over the MongoDB created one is, that I want to prevent duplicate entries for products. I get the JSON Product objects through a cronjob triggered call on an external API, including already existing ones. Maybe there is another, better way to do this?
You are defining an field as an ObjectID, but you are assigning a Number to it. To create an ObjectID you need to do something like:
new ObjectId('something');
However, in your case this is probably not the best idea. Define your model like this:
var Product = new Schema({
external_id: {type: Number, unique: true},
name: {type: String},
});
You can specify unique on a field to create a unique index for that field.
In the question you've mentioned,
The object is stored fine in the "products" collection, but the id from the JSONProduct is replaced by a MongoDB created value:
{ "id" : ObjectId("119894980274616772006500"), "name" : "The Foo Bar" }
But I think the it is created as:
{ "_id" : ObjectId("119894980274616772006500"), "name" : "The Foo Bar" }
Also, you can pass in your product id to field by name "_id", then mongo will not create any separate IDs and it'll not accept duplicate values and it'll have indexing automatically for that field.
But make sure you push unique values of product id to _id.