Mongoose one-to-many - node.js

can you explain me how to organize mongoose models to create one to many connections? It is needed keep separate collections.
suppose i have stores and items
//store.js
var mongoose = require('mongoose');
module.exports = mongoose.model('Store', {
name : String,
itemsinstore: [ String]
});
//item.js
var mongoose = require('mongoose');
module.exports = mongoose.model('Item', {
name : String,
storeforitem: [String]
});
Am i doing it in the right way?
And how to access pass data to arryas?
Here is the code yo enter name to item. But how to enter id to array of id's (itemsinstore)?
app.post('/api/stores', function(req, res) {
Store.create({
name: req.body.name,
}, function(err, store) {
if (err)
res.send(err);
});
})

You should use model reference and populate() method:
http://mongoosejs.com/docs/populate.html
Define your models:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var storeSchema = Schema({
name : String,
itemsInStore: [{ type: Schema.Types.ObjectId, ref: 'Item' }]
});
var Store = mongoose.model('Store', storeSchema);
var itemSchema = Schema({
name : String,
storeForItem: [{ type: Schema.Types.ObjectId, ref: 'Store' }]
});
var Item = mongoose.model('Item', itemSchema);
Save a new item into an existing store:
var item = new Item({name: 'Foo'});
item.save(function(err) {
store.itemsInStore.push(item);
store.save(function(err) {
// todo
});
});
Get items from a store
Store
.find({}) // all
.populate('itemsInStore')
.exec(function (err, stores) {
if (err) return handleError(err);
// Stores with items
});

You can do using the best practices with Virtuals.
Store.js
const mongoose = require('mongoose')
const Schema = mongoose.Schema
const StoreSchema = new Schema({
name: {
type: String,
required: true
},
createdAt: {
type: Date,
default: Date.now
}
})
StoreSchema.virtual('items', {
ref: 'Item',
localField: '_id',
foreignField: 'storeId',
justOne: false // set true for one-to-one relationship
})
module.exports = mongoose.model('Store', StoreSchema)
Item.js
const mongoose = require('mongoose')
const Schema = mongoose.Schema
const ItemSchema = new Schema({
storeId: {
type: Schema.Types.ObjectId,
required: true
},
name: {
type: String,
required: true
},
createdAt: {
type: Date,
default: Date.now
}
})
module.exports = mongoose.model('Item', ItemSchema)
StoreController.js
const Store = require('Store.js')
module.exports.getStore = (req, res) => {
const query = Store.findById(req.params.id).populate('items')
query.exec((err, store) => {
return res.status(200).json({ store, items: store.items })
})
}
Keep in mind that virtuals are not included in toJSON() output by default. If you want populate virtuals to show up when using functions that rely on JSON.stringify(), like Express' res.json() function, set the virtuals: true option on your schema's toJSON options.
// Set `virtuals: true` so `res.json()` works
const StoreSchema = new Schema({
name: String
}, { toJSON: { virtuals: true } });

Okay, this is how you define a dependancy:
var mongoose = require('mongoose');
module.exports = mongoose.model('Todo', {
name : String,
itemsinstore: [{ type: Schema.Types.ObjectId, ref: 'Item' }]
});
And make sure you have different names:
var mongoose = require('mongoose');
module.exports = mongoose.model('Item', {
name : String,
storeforitem: [String]
});
Keep an eye on Item in both cases.
And then you just want to pass the array of ObjectIDs in it. See more here: http://mongoosejs.com/docs/populate.html

Try this:
Store.findOne({_id:'5892b603986f7a419c1add07'})
.exec (function(err, store){
if(err) return res.send(err);
var item = new Item({name: 'Foo'});
item.save(function(err) {
store.itemsInStore.push(item);
store.save(function(err) {
// todo
});
});

Related

I can't handle populate in mongoose

I think it's not populating categories couse when i try log 'category' in console i get
"ReferenceError: category is not defined". For me it is like in docs but as we see it's not. Is anyone can tell me what is wrong??
//model/Category.js
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const CatSchema = new Schema({
title: {
type: String,
required: true
},
body: {
type: String,
required: true
}
});
mongoose.model("categories", CatSchema, "categories");
model/Story.js
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const StorySchema = new Schema({
title: {
type: String,
required: true
},
body: {
type: String,
required: true
},
category: {
type: Schema.Types.ObjectId,
ref: "categories"
}
});
mongoose.model("stories", StorySchema, "stories");
routes/stories.js
const express = require('express');
const router = express.Router();
const mongoose = require('mongoose');
const Category = mongoose.model('categories');
const Story = mongoose.model('stories');
router.get('/add', (req, res) => {
Story.find()
.populate('category', 'title')
.then(stories => {
res.render('stories/add', {
stories: stories
});
});
});
Query.prototype.populate() returns a Query object on which you need to run .exec(), try this:
Story.find({})
.populate('category', 'title')
.exec()
.then(stories => {
res.render('stories/add', {
stories: stories
});
});
It was problem with that how I want to use it. Code is working

Nodejs Mongodb update multiple collections

In mongodb have two collections for now Event and Packages. So basically the model looks like this
Event Model
const mongoose = require('mongoose');
mongoose.Promise = global.Promise;
const Schema = mongoose.Schema;
const bcrypt = require('bcrypt-nodejs');
const EventSchema = new Schema({
_id: mongoose.Schema.Types.ObjectId,
eventname: {
type: String,
required : true,
},
eventdesc: {
type: String,
required : true,
},
createdAt: {
type: Date,
default: Date.now
},
updatedAt: {
type: Date,
default: Date.now
}
});
module.exports = mongoose.model('Event', EventSchema);
Package Model looks like this
const mongoose = require('mongoose');
mongoose.Promise = global.Promise;
const Schema = mongoose.Schema;
const bcrypt = require('bcrypt-nodejs');
const PackageSchema = new Schema({
_id: mongoose.Schema.Types.ObjectId,
eventpackages: {
type: Object,
required : false,
},
event: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Event'
},
createdAt: {
type: Date,
default: Date.now
},
updatedAt: {
type: Date,
default: Date.now
}
});
module.exports = mongoose.model('Package', PackageSchema);
Here I am trying to update an event so when the event will be updated the packages will be updated also. So in nodejs I have done like this
var express = require('express');
var router = express.Router();
var mongoose = require('mongoose');
/* UPDATE EVENT */
router.put('/:id', function(req, res, next) {
upload(req, res, function(err) {
let EventData = {
eventname : req.body.eventname,
eventdesc : req.body.eventdesc,
}
let EventPackages = {
eventpackages : req.body.sections,
}
Event.findByIdAndUpdate(req.params.id, EventData, function (err, post) {
if (err) return next(err);
Package.findAndModify({
query: { event: req.params.id },
update: { $inc: { EventPackages } },
new: true,
upsert: true
})
res.json(post);
});
});
});
module.exports = router;
But its not working at all. If I will deleted the codes for package update it will work for events.
So can someone tell me how to make this work so that I can update multiple collections at a time.
you can try this,
var query = {
'event': req.params.id
};
var dataToUpdate = {
$set: {
///
}
};
Package.updateMany(query, datatoUpdate, function(err, result) {
if (err) return handleError(err);
return Promise.resolve(result);
});

Mongoose populate empty collection with other collections

I am trying to create a method for populating collection with a pre-defined Schema static method. I want it to grab all documents from 2 different collections and return them. It seems logical to me to create a separate Schema and return this.find().populate() callback as a result, but I can't get it to work...
Here are my Schemas:
dht.model.js
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
// Dht Schema from MongoDB
var DhtSchema = mongoose.Schema({
location: {
type: String,
required: true
},
reading: {
type: String,
required: true
}
}, {
timestamps: {
createdAt: 'created_at',
updatedAt: 'updated_at'
},
});
co2.model.js
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
// CO2 Schema from MongoDB
var CO2Schema = mongoose.Schema({
location: {
type: String,
required: true
},
reading: {
type: String,
required: true
}
}, {
timestamps: {
createdAt: 'created_at',
updatedAt: 'updated_at'
},
});
excel.model.js
This is the schema I want to populate dynamically, since new data is added to the database from MQTT middleware every 20 minutes and it has to return old and new results every time it has been invoked.
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
// Dht Schema from MongoDB
var ExcelSchema = mongoose.Schema({
co2: [{
type: Schema.ObjectId,
ref: 'co2'
}],
dht: [{
type: Schema.ObjectId,
ref: 'dhts'
}]
});
ExcelSchema.statics.showAll = function (cb) {
return this.find().populate('co2 dht').exec(function (err, cb) {
if (err) {
return err;
}
return cb;
});
};
module.exports = mongoose.model('merged_sensors', ExcelSchema);
When method is invoked within the API, it freezes and returns 504. My only assumption is, that it can't access the collections for some reason, but I am, most likely, wrong.
Update:
Here is a controller, which makes an API call for that Collection:
excel.controller.js
var Xls = require('./../models/excel.model'),
express = require("express"),
router = express.Router();
router.get("/all", function (req, res) {
Xls.showAll(function (err, results) {
if (err) throw err;
res.json(results);
})
});
module.exports = router;

Populate and Virtuals with mongoose returning incomplete data

I need some help with populate and virtuals with mongoose.
When I get a list of the "cidade" using
router.get('/',function(req,res,next){ ....
I'd like to populate the result with some additional info from "estado" as "_id " and "nome".
But, when I print the results in the console, I have only results from "cidade" and no data informations from "estado".
The relation between 'cidade" and "estado" is N:1 and the field 'uf' is the link to both collections.
What am I doing wrong?
Following is the collections data sample
//cidades
"_id":213123......
"uf":"AL"
"cidade":"ARARAS"
......
//estados
"_id":2aaa3123......
"uf":"AL"
"nome":"AZALU"
.....
//router to cidades
'use strict';
const express = require('express');
const router = express.Router();
//const querystring = require('querystring');
const Cidade = require('../models/cidade');
const callback=function(err,data,res){
console.log(data);//??? only data from "cidade", no "estado" info
if (err) return res.status(500).json(err);
return res.status(200).send(data);
};
router.get('/',function(req,res,next){
const query=new RegExp(req.query.where,'i');
Cidade.find({ cidade: query })
.populate('id_estado')
.exec( (err,data) => {
callback(err,data,res)
})
});
//model estados
estadosSchema = new mongoose.Schema({
uf: {type: String, unique:true},
nome: {type: String, unique:true}
});
module.exports = mongoose.model('Estado', estadosSchema,'estados' );
//model cidades
cidadesSchema = new mongoose.Schema({
uf: {type: String, unique:true},
cidade: {type: String, unique:true}
},{ toJSON: { virtuals: true } });
cidadesSchema.virtual('id_estado', {
ref: 'Estado', // The model to use
localField: 'uf', // Find Estado where `localField`
foreignField: 'uf', // is equal to `foreignField`
justOne: false
});
module.exports = mongoose.model('Cidade', cidadesSchema,'cidades' );

cant get data from database after multiple schema declared (mongoose + express + mongodb

I'm new to node.js and I am having problem accessing to the when multiple mongoose schema were declare.
//schema.js in model
var mongoose = require('mongoose');
var Schema = mongoose.Schema
, ObjectId = Schema.ObjectId;
//User Schema
var userSchema = new Schema({
id: ObjectId,
firstname: {type: String, require: true},
lastname: {type: String, require: true},
username: {type: String, unique: true, require: true},
password: {type: String, require: true},
role: {type: [String], require: true}
})
var User = mongoose.model('User', userSchema);
module.exports = User;
//Question Schema
var qnSchema = new Schema({
id: ObjectId,
question: {type: String, require: true},
module_id: {type: ObjectId, ref: 'Module'}
})
var Question = mongoose.model('Question', qnSchema);
module.exports = Question;
//Answer Schema
var ansSchema = new Schema({
id: ObjectId,
answer: String,
question: {type: ObjectId, ref: 'Question'}
})
var Answer = mongoose.model('Answer', ansSchema);
module.exports = Answer;
//Module Schema
var modSchema = new Schema({
id: ObjectId,
name: {type: String, require: true}
})
var Module = mongoose.model('Module', modSchema);
module.exports = Module;
//Role Schema
var roleSchema = new Schema({
id: ObjectId,
role: {type: String, require: true}
})
var Role = mongoose.model('Role', roleSchema);
module.exports = Role;
//index.js in controller
var mongoose = require('mongoose');
var User = require('../models/schema');
var db = mongoose.connect('mongodb://localhost/damai');
module.exports = function(app) {
app.get('/', function(req, res) {
if (typeof req.session.userid == 'undefined') {
res.render('login', { title: app.get('title') });
} else {
res.render('index', { title: app.get('title') });
}
});
app.post('/login', function(req, res) {
passwordVerification(req, res);
});
}
function passwordVerification(req, res)
{
var userid = req.param('userid');
var password = req.param('password');
User.findOne({'username': userid},{'password': 1}, function(err, cb)
{
console.log(cb);
if(cb!= null)
{
if (password == cb.password) {
req.session.userid = userid;
res.render('index', { title: app.get('title'), 'userid': userid });
} else {
res.render('login', { title: app.get('title'), error: 'Invalid login'});
}
}
else
{
res.render('login', { title: app.get('title'), error: 'Invalid login'});
}
});
}
When I only have the "User Schema" in my schema.js, the database call from method "passwordVerification()" from index.js will return me the relevant password that was retrieve from the database. However, when I start adding in other schema such as "Question Schema" in schema.js, the method "passwordVerification()" will always return null.
When exporting multiple models from a single file like you are in schema.js, you need to give each exported model its own exports field name.
For example, replace the multiple module.exports = ... lines in schema.js with this code at the end of the file that exports all models:
module.exports = {
User: User,
Question: Question,
Answer: Answer,
Module: Module,
Role: Role
};
And then in index.js you can access the models like so:
var models = require('./schema');
...
models.User.findOne(...

Resources