Additional field in array of _id's referencing another collection - mongodb

this is what I have and it works:
var comboSchema = new Schema({
components: [{
type: Schema.Types.ObjectId,
ref: "Component"
}]
})
This is what I want to achieve:
var comboSchema = new Schema({
components: [{
type: Schema.Types.ObjectId,
ref: "Component",
amount: {type: Integer}
}]
})
Is it possible in MongoDB, if not what is the best workaround?
Thank you :-)

This schema work because of an element or filed name is provided
var comboSchema = new Schema({
components: [{
type: Schema.Types.ObjectId,
ref: "Component"
}]
})
Now you made a single mistak you want to create schema name without name in object with two different filed
Right way to create schema like this is to make other variable inside of array which contain type of filed
var comboSchema = new Schema({
components: [{
id: {
type: Schema.Types.ObjectId,
ref: "Component"
},
amount: { //If you want to make every component amount
type: Number
}
}]
})
Or
var comboSchema = new Schema({
amount: { type: Number },
//If you want to make only single amount on multiple components
components: [{
componentId: {
type: Schema.Types.ObjectId,
ref: "Component"
}
}]
})
But in both case you can't populate directly. You need to use aggregation for that to get data for embedded documents.

Related

Moongose: .populate on key with white space doesn't work

I'm using Express and Mongoose to do some database actions. When trying to populate a path where the key includes a whitespace, it basically get's ignored.
MongoDB Model:
const OrgCrimeSchema = new Schema({
gracePeriod: { type: Date, default: Date.now() },
Technical: {
description: String,
difficulty: Number,
owner: { type: Schema.Types.ObjectId, ref: 'User' },
},
'Social Engineering': { // This one causes issues
description: String,
difficulty: Number,
owner: { type: Schema.Types.ObjectId, ref: 'User' },
},
});
Find + Populate:
const now = Date.now();
const allOrgCrimes = await OrgCrime.find({ gracePeriod: { $lte: now } })
.populate('Technical.owner', 'name')
.populate('Social Engineering.owner', 'name');
console.log(allOrgCrimes['Social Engineering'][0].owner);
//5fca3b4a86e77b5c8e58b683
console.log(allOrgCrimes['Technical'][0].owner);
// { name: 'npc_alice', _id: 5fae6d7ee60018434108369c }
I assume the path is not being populated because of a white space in the key. I've tried both dot notation and typing {path: 'Social Engineering', select: 'name -id'}, without luck.
Is there any way around this without having to rewrite the schema structure?
In short, there is no way, if we wanted to populate multiple paths at the same time there is this way
for exmaple
Story
.find(...)
.populate('book author') // space delimited path names
.exec()
you can see space delimited path names.
When you pass a key with space,mongoose consider it as populate multiple
As poined out by Mohammad Yaser Ahmadi, there is no solution to this issue today because of populate assumes you're populating multiple instead of trying to read a path name with a space in between. How I 'solved' this was to rewrite the model to this:
const OrgCrimeSchema = new Schema({
gracePeriod: { type: Date, default: Date.now() },
roles: [{
role: String,
description: String,
difficulty: Number,
owner: { type: Schema.Types.ObjectId, ref: 'User' },
}]
})
And then the populate actually get's easier:
.populate('roles.owner', 'name')

Collection referencing multiple collections

I want to have a collection with multiple fields referencing multiple collections, something like it:
var comboSchema = new Schema({
oneId: { type: Schema.Types.ObjectId, ref: "One" },
twoId: { type: Schema.Types.ObjectId, ref: "Two" },
threeId: { type: Schema.Types.ObjectId, ref: "Three" },
components: {
id: {type: Schema.Types.ObjectId, ref: "Component"},
amount: {type: Number}
}
}
I know I can use $lookup and aggregate to get data, but it looks like it works only on a single field in a collection?
Any help? Thank you! :-)
This is a model sample using the ref, the ref key in the object will take the name of the model in which you are referencing
const mongoose = require('mongoose');
const postSchema = mongoose.Schema({
text: {
type: String,
required: 1
},
mediatype: {
type: String,
required: 1
},
media: {
type: String,
required: true
},
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'user'
},
likes: {
type: [{
userid: {
type: mongoose.Schema.Types.ObjectId,
ref: 'user'
}
}]
},
comments: {
type: [{
userid: {
type: mongoose.Schema.Types.ObjectId,
ref: 'user'
},
comment: String
}]
},
}, {
timestamps: true
})
const Post = mongoose.model('post', postSchema)
module.exports = Post
so you can then populate it like Post.find().populate('user')

Retrieve relationship from a child instance on MongoDB

In MongoDB, I have a One-To_many reference relationship.
A has many B.
A has a property called B_ids, so I can retrieve all the B instances owned by a a particular A instance.
My question is: looking to an instance of B, how can I retrieve the A instance that owns it?
Thanks!
In order to do that you can try this:
var personSchema = Schema({
_id: Schema.Types.ObjectId,
name: String,
age: Number,
stories: [{ type: Schema.Types.ObjectId, ref: 'Story' }]
});
var storySchema = Schema({
author: { type: Schema.Types.ObjectId, ref: 'Person' },
title: String,
fans: [{ type: Schema.Types.ObjectId, ref: 'Person' }]
});
in this way you can retrieve A from B using populate.
Story.find().populate('author')
Example borrowed from mongoose populate website.

MongooseError: Cannot read property 'options' of undefined when setting reference

Trying to set a simple reference field in Mongoose is giving me huge problems.
I get the following error. As far as I can tell there are no actual validation errors.
'contents.0.modules.0.matches.0.':
{ MongooseError: Cannot read property 'options' of undefined
at ValidatorError (C:\Users\Simon\Documents\Projects\eventvods\node_modules\mongoose\lib\error\validator.js:24:11)
at _init (C:\Users\Simon\Documents\Projects\eventvods\node_modules\mongoose\lib\document.js:372:37)
...
at init (C:\Users\Simon\Documents\Projects\eventvods\node_modules\mongoose\lib\document.js:348:7)
at model.Document.init (C:\Users\Simon\Documents\Projects\eventvods\node_modules\mongoose\lib\document.js:313:3)
message: 'Cannot read property \'options\' of undefined',
name: 'ValidatorError',
properties: [Object],
kind: 'cast',
path: undefined,
value: undefined } } }
Mongoose schema like so
var matchSchema = new Schema({
team1: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Teams'
},
team2: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Teams'
},
team1_2: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Teams'
},
team2_2: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Teams'
},
...
});
var moduleSchema = new Schema({
matches: [matchSchema],
...
});
var sectionSchema = new Schema({
modules: [moduleSchema],
...
});
A sample object that fails to save:
{
team1: 5835a5f653d4ce23bb33ab19,
team2: 5835a70353d4ce23bb33ab21
}
So this was a weird one, but I was able to bypass it with a little awkward manipulation.
Creating a new schema field of the same type, and setting that to
the value.
Going through all my documents, and setting the
original field to that field's value.
this is your team1 definition:
team1: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Teams'
}
and this is your data in mongo:
team1: 5835a5f653d4ce23bb33ab19
As you can see, team1 object type is not ObjectId! it's just a normal String!
Mongo stores a reference like this:
team1: {
"$ref" : "Teams",
"$id" : ObjectId("5835a5f653d4ce23bb33ab19")
}
So either fix your data in mongo or fix your scheme!
You have not defined your schema correctly. It should be more like so:
var matchSchema = new Schema({
team1: {
type: mongoose.Schema.Types.ObjectId,
ref: String
},
team2: {
type: mongoose.Schema.Types.ObjectId,
ref: String
},
team1_2: {
type: mongoose.Schema.Types.ObjectId,
ref: String
},
team2_2: {
type: mongoose.Schema.Types.ObjectId,
ref: String
},
...
});

Mongoose.js: is it possible to populate array items by condition?

I have this schema:
var PostSchema = new Schema({
by: { type: mongoose.Schema.Types.ObjectId, ref:'user' },
body: String,
likes: [{ by: { type: mongoose.Schema.Types.ObjectId, ref:'user' }, isAnonymous: { type: Boolean, default: false}}],
});
This schema supports anonymous likes.
my question: is there a way to populate only the items in the 'likes' array where isAnonymous is equals to false?
Yes, There is
opts={
path: 'likes',
match: {
isAnonymous:false
},
select: '<fields to be fetched>'
};
Post
.find({})
.populate(opts)
docs
help