Can database references in mongodb reference two databases? - mongodb

I am using MongoDB via mongooose. Can database references reference two databases at the same time?
field_name: {
type: mongoose.Schema.Types.ObjectId,
ref: 'collectionA',// can I reference collectionA and collectionB too?
required: true,
},
See code above.
The field, field_name, can be an objectId from collectionA or collectionB. How can I reflect that in my mongoose schema?

I guess you are looking for mongoose dynamic reference via refPath.
const someSchema = new Schema({
field_name: {
type: Schema.Types.ObjectId,
required: true,
refPath: 'onCollection'
},
onCollection: {
type: String,
required: true,
enum: ['collectionA', 'collectionB']
}
});
In this case, Instead of a hardcoded model name in ref, refPath means Mongoose
will look at the onCollection property to find the right model.
For example if we have this document:
{
field_name: some_id,
onCollection: 'collectionA'
}
Collection.find().populate('field_name') will populate the field from collectionA. And if the onCollection field was valued with collectionB, it would have populated it from collectionB.
This scenario only works if you want to reference one collection at a time, but the collection is dynamic.
If you need to reference both collections at the same time, there is no mongoose schema design to support array of references as far as I know.
You can just ignore ref in your schema, and pass in the value of ref when you want to populate:
populate({
path: 'field_name',
model: 'collectionA'
})
Then you can have multiple populates. Same applies for $lookup.

Related

Populate multiple fields using lookup in mongodb

I am new to mongodb and wanted to populate two ids using lookup
Eg:
{
"sampleId1": "5kjksds8nkjfhsjfi8kl",
"sampleId2": "7jhjshfi9jsfkjsdfkkk"
}
I am using aggregate framework to query the data and wanted to popualte both ids.
I want $loopup to populate both ids which is similar to
Model.find().populate('sampleId1').populate('sampleId2')
For your case, I want to suggest you mongoose-autopopulate like this
const autopopulate = require('mongoose-autopopulate')'
const sampleSchema = new Schema({
sampleId1: {type: Schema.ObjectId, ref: 'ColleactionName', autopopulate: {select: 'firstName, lastName'}},
sampleId2: {type: Schema.ObjectId, ref: 'ColleactionName', autopopulate: {select: 'firstName, lastName'}}
})
sampleSchema.plugin(autopopulate)
module.exports = mongoose.model('sampleSchema', sampleSchema)
now whenever you request for find it automatically populates all field
who have Schema.ObjectId
let criteria = {},
projection = {},
options = {lean: true}
Model.find(criteria, projection, options, (err, result) => {
console.log(result); // See out-put
})
The second thing you need to check in your schema that sampleId1 and sampleId2 both have type type: Schema.ObjectId with reference of collection name ref: 'ColleactionName'
the second way to this thing which you already have done you question
sampleSchema.
find(...).
populate('sampleId1').
populate('sampleId2').
exec();

Mongoose mixed SchemaType

I couldn't understand that for what purpose mongoose schemaType is used for. If someone could explain it will be helpful.
I'm have to reference another schema from a schema i want to know if we can get the details of all schema together when we do a findOne() on mongoose.
mixed schema means whatever you want the type to be. if you input a String, Number, Date, mongoose will let you do that. However according to documentation, mongoose ref does not work with mixed.
Note: ObjectId, Number, String, and Buffer are valid for use as refs.
if you use mixed, and ref it, you won't be able to query it back.
If you start all over(delete the database and reinsert again), use ObjectId instead of Mixed.
var storySchema = Schema({
author : { type: ObjectId, ref: 'Person' },
});
If you wish to retain old database, the best way is to change mixed to string
var storySchema = Schema({
author : { type: String, ref: 'Person' },
});

How to dynamically populate mongoose document reference at runtime?

I have a schema that has a field that could reference different schema.
var HistorySchema = new Schema({
type: {type: String, required: true},
objectId: {
type: Schema.Types.ObjectId,
required: true,
},
changed: {type: Schema.Types.Mixed}
})
The documents of this schema allows me to keep track of changes happens in different types of objects with objectId.
For example, if User has changed name from 'John' to 'Steve', a History document would have:
{
type: 'User',
objectId: '55fa6bf0831ba3fa0879e7e8',
changed: {name: {oldValue: 'John', newValue: 'Steve'}}
}
Obviously, type can be many different things.
My question is, can I magically populate the objectId field without knowing type before the query?
I know I can do:
History.query({...}).populate('objectId', null, 'User').exec(...);
But that requires me to know the type is User when the query is constructed.
And obviously I can do a second query manually given the type and objectId.
For example, is it possible to save the ref type of a document (not schema) at runtime and take advantage of that? I look around and don't seem to find a way.

Does using dbref do anything more than just storing an `id`

My Mongoose schema:
// set up the schema
var CategorySubSchema = new Schema({
name: { type: String },
_category_main : { type: String, ref: 'CategoryMain' }
},
And my controller code:
CategorySub.create({
name : req.body.name,
_category_main : req.body.category_main
}, function(err, data){
An entry in my db:
{
"_id": "54dd163434d78ae58f6b1a69",
"name": "Snacks",
"_category_main": "54dcf4a71dfecb4d86ddcb87",
"__v": 0
},
So I used an underscore, because I was following an example. Does this mean anything to the database or is it just convention for references?
Also, instead of passing the entire JSON object in the request - req.body.category_main, why not just pass and id and change my schema to this?:
var CategorySubSchema = new Schema({
name: { type: String },
category_main_id : { type: String }
},
In short, Yes.
The below schema definition is an example of Manual references.
var CategorySubSchema = new Schema({
name: { type: String },
category_main_id : { type: String }
}
where,
you save the _id field of one document in another document as a
reference. Then your application can run a second query to return the
related data. These references are simple and sufficient for most use
cases.
In this case, we need to write explicit application code to fetch the referred document and resolve the reference. Since the driver that we use wouldn't know about the collection in which the referred document is present nor the database in which the referred document is present.
When you define the schema as below, this is an example of storing the details of the referred document .(Database references)
var CategorySubSchema = new Schema({
name: { type: String },
_category_main : { type: String, ref: 'CategoryMain' }
}
They include the name of the collection, and in some cases the
database name, in addition to the value from the _id field.
These details allow various drivers to resolve the references by themselves, since the name of the collection and the database(optional) of the referred document would be contained in the document itself, rather than we writing explicit application code to resolve the references.
So I used an underscore, because I was following an example. Does this mean anything to the database or is it just convention for
references?
Using underscore in the _id field is a valid naming convention, but mongoDb doesn't explicitly mention about the naming convention of other fields which are used to resolve references. You could just use any other field name as long as it conforms to this.

Mongoose OR operator for schema definitions

Does Mongoose support, or is there an available package that supports multiple "options" for the embedded schemas in an array?
For example, the things property can contain only one of two schemas:
new Schema({
things: [{
requiredProp: String,
otherProp: Number
}, {
otherOption: Number
}]
});
In other words, I do not want to just allow anything (AKA Schema.Types.Mixed) to be stored in this property, but only these two possible definitions.
Or, do schema design recommendations exist to avoid this problem?
You should only define one dict in the array type of the schema, and then set if they are required or not with the mongoose schema types logic. Use pre save if you want to do more logic to assure that either one of the fields have been set, like this:
var MySchema = new Schema({
things: [{
requiredProp: {type: String, required: true},
otherProp: Number,
otherOption: Number,
}]
});
MySchema.pre('save', function(next) {
if (!this.otherProp && !this.otherOption) {
next(new Error('Both otherProp and otherOption can\'t be null'))
} else {
next()
}
})
Opon saving the object it will return an error if neither otherProp nor otherOption has been set.