Mongoose not populating array in Mongodb - node.js

Here is my Game Schema :
var mongoose = require('mongoose');
const GameSchema = new mongoose.Schema({
title: {
type: String,
required: true
},
publishers: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'Publisher'
}
]
});
var GameModel = mongoose.model('Game', GameSchema);
module.exports = GameModel;
Here is my Publisher Schema :
var mongoose = require('mongoose');
const PublisherSchema = new mongoose.Schema({
companyName: {
type: String,
required: true
},
firstParty: {
type: Boolean,
required: true
},
website: {
website: String,
}
});
var PublisherModel = mongoose.model('Publisher', PublisherSchema);
module.exports = PublisherModel;
I have a picture of what you can find in my collection "games" in mongoDB :
When I use this route :
router.get('/games', async function(req, res) {
const games = await Game
.find()
.populate('publishers')
.select('title publishers')
res.json(games);
})
I have empty arrays as result for the publishers. If I don't use an array in Schema, this is correcly populated and I got data of publisher into each game. So why mongoose doesn't populate when it is an array?

Check below by modifying the schema definition as below
I think the below could fix your issue, please give a try by redefining the publishers as below
Publishers: [
publisher: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Publisher'
}
]

I think the definition of schema is more about to define the structure of the object that we would like to process, rather about the number of objects that we want to process.
The Schema definition with what I know is defining the semantics of the model and to take advantage of the middle ware functionalities.
You can save multiple objects of which meet the same semantic definition but the definition itself cannot be an array
Thanks
Pavan

Related

Can I set a element of my mongoose model to be strictly of some particular other models?

My subsection model should strictly be a type of lecture or quiz model only.
I want something like this. Any idea how to implement it properly?
const mongoose = require("mongoose");
const { ObjectId } = mongoose.Schema;
const subSectionSchema = new mongoose.Schema({
subSection:{
type:ObjectId,
enum:["Lecture","Quiz"]
}
});
module.exports = mongoose.model("SubSection", subSectionSchema);
Although I can always do this way...check which type it is and set that value.
const mongoose = require("mongoose");
const { ObjectId } = mongoose.Schema;
const subSectionSchema = new mongoose.Schema({
lecture: {
type: ObjectId,
ref: "Lecture",
},
quiz: {
type: ObjectId,
ref: "Quiz",
},
});
module.exports = mongoose.model("SubSection", subSectionSchema);
But I am looking for something simple.
I'm not sure if I understood your question, but I think what you're looking for are dynamic references. This feature allow us to have dynamic properties on our MongoDB collection.
You'll basically need two properties for it, one for the ObjectID, other for the reference. Whenever you need to populate the reference, it will automatically detects which entity/collection to use.
Here's a quick example from Mongoose docs:
const commentSchema = new Schema({
body: { type: String, required: true },
on: {
type: Schema.Types.ObjectId,
required: true,
// Instead of a hardcoded model name in `ref`, `refPath` means Mongoose
// will look at the `onModel` property to find the right model.
refPath: 'onModel'
},
onModel: {
type: String,
required: true,
enum: ['BlogPost', 'Product']
}
});
const Product = mongoose.model('Product', new Schema({ name: String }));
const BlogPost = mongoose.model('BlogPost', new Schema({ title: String }));
const Comment = mongoose.model('Comment', commentSchema);

Mongoose schemas cast error when adding a new category

I have two schemas, one collection and another category. A collection has many category and a category can have many collection items.
I'm looking to create a filter later on down the line.
category schema
const mongoose = require('mongoose')
let categorySchema = new mongoose.Schema({
name: {
type: String,
required: true,
unique: true
},
collections: [{ type: mongoose.Types.ObjectId, ref: 'Collection' }]
})
module.exports = mongoose.model('category', categorySchema)
collection schema
const mongoose = require('mongoose')
let collectionSchema = new mongoose.Schema({
...
categories: [{
type: mongoose.Schema.Types.ObjectId, ref: 'categories',
required: true
}]
})
module.exports = mongoose.model('collection', collectionSchema)
truncated this to keep it relevant.
I'm not looking to populate the references yet as I'm only doing the backend for now, so I'm only rendering JSON for now.
I can create multiple category
and I can create a collection with a category as a collection must have at least one category
I can edit a collection and add a new category
However, sometimes I seem to get the following error
I'm not sure why maybe the database hasn't updated in the app, I am using nodemon so I'm not really sure what the issue could be here.
const CollectionSchema = new Schema({
name: String
categoryName: String
});
const CategorySchema = new Schema({
name: String
});
CollectionSchema.virtual('category', {
ref: 'Category', // The model to use
localField: 'name', // Find people where `localField`
foreignField: 'categoryName', // is equal to `foreignField`
// If `justOne` is true, 'members' will be a single doc as opposed to
// an array. `justOne` is false by default.
justOne: false,
options: { sort: { name: -1 }, limit: 5 } //you can add options as well
});
const Category = mongoose.model('Category', CategorySchema);
const Collection = mongoose.model('Collection', CollectionSchema);
Collection.find({}).populate('category').exec(function(error, categories) {
/* `categories.members` is now an array of instances of `Category` */
});
This link has additional Information

How to connect schemas with each other in mongooseJS?

Basically what I am trying to achieve is the following:
In my iOS application a QR-Code can be scanned to get the ID of a specific lounge and with that its JSON data (only ID and name for now) saved in MongoDB.
Every lounge is able (but doesn't have to) to add products to their lounge, so that in the end, after scanning the QR-Code, a customer is able to see which products are offered.
A product contains only a name and imageURL for now, but not a price, because the price can variate and be set by owners of a lounge. So a price of one and the same product can be different.
I would like to know, what the correct and best way is for implementing the schemas for that approach, so that I can easily fetch all products of a specific lounge, maybe based on its ID.
What I got so far:
lounge.js:
const mongoose = require('mongoose');
const loungeSchema = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
name: { type: String, required: true }
});
module.exports = mongoose.model('Lounge', loungeSchema);
product.js
const mongoose = require('mongoose');
const productSchema = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
name: { type: String, required: true },
imageURL: { type: String, required: true, unique: true }
});
module.exports = mongoose.model('Product', productSchema);
Basically you can use mongoose populate. You can achieve this by storing the products in separate collection and basically populate an array on the lounge schema using the _id for the lounge let me show you an example:
Your lounge schema would be something like this
const mongoose = require('mongoose');
const loungeSchema = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
name: { type: String, required: true }
products: [type: Schema.Types.ObjectId, ref: 'Products' ]
});
module.exports = mongoose.model('Lounge', loungeSchema);
And your product schema
const mongoose = require('mongoose');
const productSchema = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
name: { type: String, required: true },
imageURL: { type: String, required: true, unique: true }
});
module.exports = mongoose.model('Product', productSchema);
When saving creating a lounge just add the _id of the product to products array that apart of the lounge schema.
So basically you find the product and retrieve its _id.
To run a find query it would be something like this:
lounge.find({}).populate('products').exec();
products array will then have the related products for each lounge

Mongoose populate ObjectID from multiple possible collections

I have a mongoose model that looks something like this
var LogSchema = new Schema({
item: {
type: ObjectId,
ref: 'article',
index:true,
},
});
But 'item' could be referenced from multiple collections. Is it possible to do something like this?
var LogSchema = new Schema({
item: {
type: ObjectId,
ref: ['article','image'],
index:true,
},
});
The idea being that 'item' could be a document from the 'article' collection OR the 'image' collection.
Is this possible or do i need to manually populate?
Question is old, but maybe someone else still looks for similar issues :)
I found in Mongoose Github issues this:
mongoose 4.x supports using refPath instead of ref:
var schema = new Schema({
name:String,
others: [{ value: {type:mongoose.Types.ObjectId, refPath: 'others.kind' } }, kind: String }]
})
In #CadeEmbery case it would be:
var logSchema = new Schema({
item: {type: mongoose.Types.ObjectId, refPath: 'kind' } },
kind: String
})
But I did't try it yet...
First of all some basics
The ref option says mongoose which collection to get data for when you use populate().
The ref option is not mandatory, when you do not set it up, populate() require you to give dynamically a ref to him using the model option.
#example
populate({ path: 'conversation', model: Conversation }).
Here you say to mongoose that the collection behind the ObjectId is Conversation.
It is not possible to gives populate or Schema an array of refs.
Some others Stackoverflow people asked about it.
Soluce 1: Populate both (Manual)
Try to populate one, if you have no data, populate the second.
Soluce 2: Change your schema
Create two link, and set one of them.
var LogSchema = new Schema({
itemLink1: {
type: ObjectId,
ref: 'image',
index: true,
},
itemLink2: {
type: ObjectId,
ref: 'article',
index: true,
},
});
LogSchema.find({})
.populate('itemLink1')
.populate('itemLink2')
.exec()
Dynamic References via refPath
Mongoose can also populate from multiple collections based on the value of a property in the document. Let's say you're building a schema for storing comments. A user may comment on either a blog post or a product.
body: { type: String, required: true },
on: {
type: Schema.Types.ObjectId,
required: true,
// Instead of a hardcoded model name in `ref`, `refPath` means Mongoose
// will look at the `onModel` property to find the right model.
refPath: 'onModel'
},
onModel: {
type: String,
required: true,
enum: ['BlogPost', 'Product']
}
});
const Product = mongoose.model('Product', new Schema({ name: String }));
const BlogPost = mongoose.model('BlogPost', new Schema({ title: String }));
const Comment = mongoose.model('Comment', commentSchema);

mongoose - possible circular dependency?

I have the following mongoose models in my express app:
//dog.js
var mongoose = require("mongoose");
var dogSchema = (exports.dogSchema = mongoose.Schema({
name: { type: String, required: true },
}));
Then I import dog.js to my user.js
//user.js
var mongoose = require("mongoose");
var dog = require("./dog");
var userSchema = mongoose.Schema({
user: { type: String, required: true },
pass: { type: String, required: true },
dogs: [dog.dogSchema],
});
Now, from my routes I am creating a new user like this:
var user = require("../models/user");
var dog = require("../models/dog");
dog = new dog.Dog(dogData);
user = new user.User(data); //this will of course contain also dogData
user.save(next);
Is this the correct way to do this kind of operation? I have the feeling that I might be generating a circular dependency somehow, and anyway it does not look right to me. Any ideas on how to create sub-documents where the schema is from another model file?
You can create simultaneous references in two directions without creating circular problems. Create a reference from one document to the other using ref. From the docs:
http://mongoosejs.com/docs/populate.html
var mongoose = require('mongoose')
, Schema = mongoose.Schema
var personSchema = Schema({
_id : Number,
name : String,
age : Number,
stories : [{ type: Schema.Types.ObjectId, ref: 'Story' }]
});
var storySchema = Schema({
_creator : { type: Number, ref: 'Person' },
title : String,
fans : [{ type: Number, ref: 'Person' }]
});
var Story = mongoose.model('Story', storySchema);
var Person = mongoose.model('Person', personSchema);
Then you can then choose to load the sub document using populate
Story.find({ --your criteria-- })
.populate('_creator')
.exec(function (err, story) {../});
You can then store the 2 schemas in separate .js files and require them both

Resources