Mongoose populate empty collection with other collections - node.js

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;

Related

Need help in NodeJs and MongoDB problem (Mongoose populate is not working)

Here is my schema
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const finalDocument = new Schema({
name: {
type: String,
},
Properties: {
type: mongoose.Schema.Types.ObjectId,
ref: "Properties",
},
borrower: {
type: mongoose.Schema.Types.ObjectId,
ref: "borrowers",
},
});
var FinalDocuments = mongoose.model("finalDocument", finalDocument);
module.exports = FinalDocuments;
and here are my routes.
finalDocument
.find({})
.populate("borrower")
.exec()
.then((brws) => {
res.statusCode = 200;
res.setHeader("Content-Type", "application/json");
res.json(brws);
})
.catch((err) => {
console.log("error in getting borrowers", err);
});
and when I am calling this route, borrower is not populated. I am attaching the picture of Postman.
There seems no problem with your code.
Possible reasons are:
The collection name you mentioned in the ref => borrower: { type: mongoose.Schema.Types.ObjectId, ref: "borrowers", } in your schema may be spelling mistake or defined wrong schema name
May be borrowers collection doesn't have documents
Update your mongoose version and check

How can you render items only if matching category?

I'm trying to build an ecommerce shop using express and mongodb. I'm trying to make categories for the shop. (e.g when someone clicks a category it should only display the items corresponding to that category) I've tried multiple ways to tackle this issue but haven't found a solution.
My current code is this one:
var NFTitem = require("../models/NFTitem")
var Item = require('../models/item');
var async = require('async')
exports.item_list = function(req, res, next) {
async.parallel({
item: function(callback) {
Item.find({}).exec(callback);
},
collection_list: function (callback) {
NFTitem.find({}).exec(callback);
},
collection: function(callback) {
NFTitem.find({'_id' : req.params.id }).exec(callback)
},
thisCategory: function (callback) {
Item.find({'collectionItem' : req.params.id }).exec(callback);
},
}, function(err, results) {
res.render('item_list.jade', { title: "NFT Marketplace", collection_list: results.item});
})
}
Now the logic behind this is to find the items corresponding to the items database which is (Item) and extract it, finding only the id matching the categories database. Then we would find the id for the categories database which is (NFTitem). Then we would do and if else command so that it only shows if both ids are matching. But this method doesn't seem to work.
I've also tried filtering the thing but it displays nothing when i filter it out. I would like to know what would be the best solution for this and if there's any way I could solve this issue.
rendered website:
block content
h1= title
ul
each collection in collection_list
li
a(href=collection.url) #{collection.name}
models for items:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var ItemSchema = new Schema(
{
name: {type: String, required: true},
description: {type: String, required: true},
collectionItem: {type: Schema.Types.ObjectId, ref: 'nftitem', required: true},
price: {type: Number, required: true},
instock: {type: Number, required: true},
}
);
// Virtual for book's URL
ItemSchema
.virtual('url')
.get(function () {
return '/catalog/item/' + this._id;
});
//Export model
module.exports = mongoose.model('Item', ItemSchema);
models for collections:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var NFTItemSchema = new Schema(
{
name: {type: String, required: true},
description: {type: String, required: true},
}
);
// Virtual for book's URL
NFTItemSchema
.virtual('url')
.get(function () {
return '/catalog/nftitem/' + this.name;
});
//Export model
module.exports = mongoose.model('nftitem', NFTItemSchema);
Since the collectionItem field in Item Schema is a reference to NFTItemSchema Schema, you can query Item Collection directly. You can refactor and simplify your code like this:
const Item = require('../models/item');
exports.item_list = async (req, res, next) => {
try{
let all_items = await Item.find({collectionItem: req.params.id});
res.render('item_list.jade', { title: "NFT Marketplace", collection_list: all_items });
} catch (error) {
res.status(400).json(error: error);
}
}

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);
});

Accessing Schema.Types.ObjectId's values with Mongoose

Hi I'm learning MongoDB and how to use Mongoose,
I'm trying to build a simple Workout manager app, where workouts have a name (Eg: "Upper Body"), an email account (which is used to identify who created the workout) and array of exercise consisting of references to exercises.
I want to be able to have a query where I can access the exercise title(Eg: "Push Ups") by using just the workout name.
My workout.js Model:
var mongoose = require('mongoose');
const Schema = mongoose.Schema;
var Exercise = require('./exercise');
const workoutSchema = new Schema({
title: {type: 'String', required: true},
email: {type: 'String', required: true},
exercises: [{ type: Schema.Types.ObjectId, ref: 'Exercise' }],
});
module.exports = mongoose.model('Workout', workoutSchema);
My exercise.js Model:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var exerciseSchema = new mongoose.Schema({
title: {type: String, required: true}
}, {
timestamps: true
});
module.exports = mongoose.model('Exercise', exerciseSchema);
My Workout Controller looks like this :
var Workout = require('../models/workout');
var Exercises = require('../models/exercise');
exports.getWorkoutExercises = function(req, res) {
Workout.findOne({ title: req.params.workout_name})
.populate('exercises')
.exec((err, exercises) => {
if (err){
res.send(err);
}
/* I want to be able to return or access the exercises title */
res.json({exercises.title});
});
}
In My routes.js i have this :
workoutRoutes.get('/:workout_name', WorkoutController.getWorkoutExercises);
Any Help or tips is much appreciated !
I am not sure what you did here res.json({exercises.title}); Can you try this? Hope it works
Workout.findOne({ title: req.params.workout_name})
.populate('exercises')
.exec((err, workout) => {
if (err){
res.send(err);
} else {
res.send({ exercises: workout.exercises });
}
});
And then, on your client side, you can iterate the exercises array and access to the title of exercise

Mongoose one-to-many

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
});
});

Resources