In mongoose, currently i got 2 schema first one is product detail and the second one is inventory both schema are in seperate files
ProductDetail Schema
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var productDetailSchema = new Schema({
ProductID:{type:String,unique:true, require:true},
ProductName:{type:String, require:true},
Spec:String,
Price:String,
Unit:String,
OwnBrand:Boolean,
Inventory:{ type: Schema.Types.ObjectId, ref: 'inventoryModel'}
}, {collection:'products'});
module.exports = mongoose.model('productDetailModel', productDetailSchema)
Inventory Schema
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var inventorySchema = new Schema({
product:{ type: Schema.Types.ObjectId, ref: 'productDetailModel' },
stockLevel:Number
}, {collection:'inventory'});
module.exports = mongoose.model('inventoryModel', inventorySchema)
In this case I would want to put the inventory stockLevel in to productDetail. Like this
{
ProductID:'P701',
ProductName:'popcorn',
Spec:'Large Pack',
Price:'10.00',
Unit:'packs'
Inventory: 20
}
Therefore I've try to use the mongoose populate method
productDetail.findOne({ProductID:'P701'}).populate('Inventory').exec(function(err, doc){
if(err){
console.log(err)
}else{
console.log(doc)
}
})
This is the data that i've in my "Inventory collection"
{
"_id" : ObjectId("584f663d95dfa29bad337572"),
"ProductID": "P701",
"StockLevel": "20"
}
and the data in "ProductDetail Collection"
{
_id : ObjectId("584a3cea027c1f62da941acf"),
ProductID:'P701',
ProductName:'popcorn',
Spec:'Large Pack',
Price:'10.00',
Unit:'packs'
}
For some reason there are no error shows up but the console.log(doc) still didnt include any Inventory: stockLevel. I know I'm doing something wrong, but i've no idea where it is. What kind of key concept i'm missing inorder for this code to work? Thank you in advance
your inventory in the productDetailModel should be an ObjectId, from what you have shown here is a number(i.e. 20).
{
ProductID:'P701',
ProductName:'popcorn',
Spec:'Large Pack',
Price:'10.00',
Unit:'packs'
Inventory: 20
}
this should be like this:
Inventory : ObjectId('someId');
That's why it is not populating, because it can't find an ObjectId as 20 in the inventoryModel.
EDIT
This productDetail document has no field as inventory. Thus, it is not able to populate it.
{
_id : ObjectId("584a3cea027c1f62da941acf"),
ProductID:'P701',
ProductName:'popcorn',
Spec:'Large Pack',
Price:'10.00',
Unit:'packs'
}
It should have something like this too:
inventory : ObjectId("584f663d95dfa29bad337572");//some `ObjectId` which corresponds to `inventoryModel` document.
You need to create inventory field and save ObjectId of some inventory document in productDetail document while saving it, or may be while updating it.
Related
so I'm been making a site that has comments section, messaging, profile and shopping for the user. I been wondering about when making a schema for those functions, is it better to have all in one schema like
userSchema {
name: String,
....
....
}
or have them seperate like
userSchema {
}
commentSchema {
}
gallerySchema {
}
No one can give you clear answer for this, everyone has different views.
Basically, It depends on your project's scalability
As I see your requirement for this project
You can create a single schema and use it as embedded form, but it's not a very good idea if you are scaling the app.
My recommendation is to create the separate schema for all the tasks which will be easy to debug,scaling the app and in readable form.
Edit
If you are creating separate schema and want to connect them then you can use populate on the basis of ObjectId
See the docs to populate collections
Example
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);
Population
Story
.findOne({ title: 'Once upon a timex.' })
.populate('_creator')
.exec(function (err, story) {
if (err) return handleError(err);
console.log('The creator is %s', story._creator.name);
// prints "The creator is Aaron"
});
I am trying to make an API point that would do the following. I submit an Object ID in the path. The record with that ID is found. Then, the program looks into a certain field of this object. The field contains an ObjectID for another entry in the database. At last, I need to pull up that record and increment a certain field in it.
In short, I have a child->parent relationship between certain records and would like the ability of incrementing a certain field within the parent record by submitting the child's id to the API point.
Here is the code I had that did the basic child increment. How can I go about doing it for the parent?
router.get('/today/parent/up/:id', function(req, res){
var collection = db.get('Activity');
collection.update({
_id: req.params.id
},
{
$inc: {
"repetitions.today": 1,
"repetitions.total": 1
}
}, function(err, activity){
if (err) throw err;
res.json(activity);
});
})
First use mongo references, heres documenttion:
https://docs.mongodb.com/manual/reference/database-references/
here's mongoose documentation
http://mongoosejs.com/docs/2.7.x/docs/populate.html
Basically You need to do this:
var mongoose = require('mongoose')
, Schema = mongoose.Schema
var PersonSchema = new Schema({
name : String
, age : Number
, stories : [{ type: Schema.ObjectId, ref: 'Story' }]
});
var StorySchema = new Schema({
_creator : { type: Schema.ObjectId, ref: 'Person' }
, title : String
, fans : [{ type: Schema.ObjectId, ref: 'Person' }]
});
var Story = mongoose.model('Story', StorySchema);
var Person = mongoose.model('Person', PersonSchema);
Then you could use .populate() method, and then you could extract your populated model and make changes and save them with .save(), but remember to use it in populated model, not the parent one. For ex. You've got author which contains reference to books, so you make request
author.findOne({'name': 'King'}).populate('books').exec((err, king) => {
let book0 = king.books[0];
book0.title = 'I need to change this one';
book0.save((err, data) => {
console.log('saved referenced object')
}
})
Allora, I'm using mongoose for the first time and I decided to create 2 schemes: the first one represents a user and the second one represents his enquires. Users have an array of enquires like:
var userSchema = new mongoose.Schema({
name: String,
enquires: { type : [Enquire.schema] , "default" : [] },
});
var enquireSchema = new mongoose.Schema({
status: {type: String, 'default': 'pending'},
enquire: String,
});
I see that if I search for an enquire and update its status, it doesn't update the same enquire on the user's array, meaning that they are different object. I don't want to save an array of IDs as it will be the same as a relational database, so I see only 1 solution which is forgetting about the enquire scheme and use only the User scheme. Is it the way mongoose works? For every relationship do I have to insert everything like nested object?
I think you should use references to achieve what you want to achieve.
For more information on mongoose references and populate see Mongoose Populate documentation.
Try this, It may help you.
User Schema :
var userSchema = new mongoose.Schema({
name: String,
enquires: [{ type : mongoose.Schema.Types.ObjectId , ref : 'Enquiry' }]//array of enquiries
});
var User = mongoose.model('User',userSchema );
module.exports = User;
Enquiry Schema :
var enquireSchema = new mongoose.Schema({
status: {type: String, 'default': 'pending'},
enquire: String,
});
var Enquiry = mongoose.model('Enquiry',enquireSchema );
module.exports = Enquiry ;
Working :
create a new Enquiry.
Push it's ID(_id) into user's enquires array.
var enquiry = new Enquiry();
enquiry.enquire = "Dummy enquiry";//set the enquiry
enquiry.save(function(err,result){
if(!err){
//push 'result._id' into users enquires array
}
});
whenever you update an enquiry, it will be automatically updated in
user's document.
use populate to retrieve user's enquiries.
You can embed sub documents (entity) which has id and is like a document or embed native array like a normal property.
And I think the correct definition for yours is :
var enquireSchema = new mongoose.Schema({
status: {type: String, 'default': 'pending'},
enquire: String,
});
var userSchema = new mongoose.Schema({
name: String,
enquires: { type : [enquireSchema] , "default" : [] },
});
If you use refs in embedded link then there are two separate collections and be like relational db's.
I'm currently trying to develop an app using mongo and node.js.
I am facing a problem when I want to build a query who use the populate option.
Here are my Schemas :
// Schema used by mongoose
var userSchema = new mongoose.Schema(
{
_id: mongoose.Schema.Types.ObjectId,
login: String,
password: String,
movies: [ { type: mongoose.Schema.Types.ObjectId, ref: movieModel} ],
admin: Boolean
},{ collection: "user" });
var movieSchema = new mongoose.Schema(
{
_id: mongoose.Schema.Types.ObjectId,
title: String,
}, { collection: "movie" });
As you can see, each user have an array of movies, this array contains valid ids of movies. What I want is to have the movies of an user. This is how I build my query :
var query = userModel.findOne({ login: req.session.user["login"] })
.populate("movies");
query.exec(function(err, user)
{
if (err)
throw err;
console.log(user.movies[0].title);
});
The query is executed successfully, but when I try to display the title of the first movie at the console.log line I got an error "TypeError: Cannot read property 'title' of undefined". I checked the documentation of mongoose and don't understand why I'm getting this error.
I would like to specify that my database contains valid data.
I put mongoose in debug mode, and this is the query that is executed :
Mongoose: user.findOne({ login: 'user' }) { fields: undefined }
Mongoose: user.find({ _id: { '$in': [ ObjectId("52e2a28949ad409834473e71"), ObjectId("52e2a28949ad409834473e79") ] } }) { fields: undefined }
The two ids on the second line are valid ids of movies. I would like to display their name.
Thanks a lot for your help.
What is the value of this: ref: movieModel?
movieModel would need to be set to the string like "Movie". See here for more information. It will need to match the identifier provided when you create the Movie model.
var Movie = mongoose.model('Movie', movieSchema);
So, you might have in a schema:
var userSchema = mongoose.Schema({
name: String,
favorite_movies: { type: Schema.Types.ObjectId, ref: 'Movie' }
});
var User = mongoose.model('User', userSchema);
I've used the string Movie in both the Schema definition and when creating the Movie type. They need to be exactly the same.
MongooseJs uses the string name of the Model to determine where to fetch the documents from when using ref and populate.
In the debug output, you can see how Mongoose is actually querying the wrong collection, as I'd expect it to be using movies.find to find the relevant Movie documents.
I have a parent and child schema that looks like:
schedule = Schema ({
from: Date,
to: Date
});
content = Schema ({
schedule: { type: Schema.ObjectId, ref: "schedule" }
name: String
});
My question is, how do I query Mongoose to return "all content, sorted by schedule.from date"?
You'll need to sort in two steps on the client, or store the date fields you want to sort on as embedded fields within the content object.
You're trying to do a collection join by using data from two collections. As MongoDB doesn't support a join, you'd need to populate the schedule field and then do a sort locally on the client. If you have very many documents, or want to do paging of data, this of course won't work.
The most efficient means would be to store the date fields in the content model so that you can perform sorting directly from a single document and collection, without the need of a join. While that may cause other issues with the schema design that you'd like to have, you may find this is the most efficient. The benefit of this denormalization process is that you can do sorting, filtering, etc. very easily and efficiently (especially if you've indexed the date fields for example).
schedule = Schema ({
from: Date,
to: Date
};
content = Schema ({
schedule: { type: Schema.ObjectId, ref: "schedule" },
schedule_data: {
from: Date,
to: Date
},
name: String
});
You could leave the schedule field in the content schema if you wanted to be able to quickly locate and update content documents (or if there were other less used or not needed for sorting/filtering).
In your case, you don't need a reference from one collection to another simply to store schedule.from & schedule.to.
Try the following :
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
mongoose.connect('mongodb://localhost/test');
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function callback () {
console.log('Mongoose connected to MongoDB\n');
content_sch = Schema ({
schedule: {
from: Date,
to: Date
},
name: String
});
var content = mongoose.model('content', content_sch);
contentObj = new content();
contentObj.schedule.from = Date.now();
contentObj.schedule.to = Date.now();
contentObj.name = 'Ryan Rife';
contentObj.save();
//Sorting; -1 to specify an ascending or 1 descending sort respectively
content.find({}).sort({'schedule.from': -1}).exec(function(err,contentDocs){
console.log(contentDocs);
});
});
You can do sorting in many ways another one is as follows which you could try:
content.find({}, null, {sort: {schedule.from: -1}}, function(err, contentDocs) {
//console.log(contentDocs);
});
Check this for more info
When to go for references to documents in other collections?
There are no joins in MongoDB but sometimes we still want references to documents in other collections (schema). Only then you need to use the ObjectId which refers to another schema and from that schema back to the parent.Example:
var personSchema = Schema({
_id : Number,
name : String,
age : Number,
stories : [{ type: Schema.Types.ObjectId, ref: 'Story' }] //Here is a link to child Schema 'Story'
});
var storySchema = Schema({
_creator : { type: Number, ref: 'Person' }, //Field which again refers to parent schema 'Person'
title : String,
fans : [{ type: Number, ref: 'Person' }] //Array which again refers to parent schema 'Person'
});
var Story = mongoose.model('Story', storySchema);
var Person = mongoose.model('Person', personSchema);
For more info check this mongoose populate docs