Mongo db, how to give object _id another collection's document - node.js

I have 2 collections called User and Location. In User, there is a location _id and this is an Object. Id also references the location collection. My question is what did I do wrong? When I call getUser function I want to see user information and the user's location information. What I need to do ?
User Schema
module.exports = (function userSchema() {
var Mongoose = require('mongoose');
var userSchema = Mongoose.Schema({
name: {
type: String,
require: true
},
surname: {
type: String,
require: true
},
tel: {
type: String,
require: true
},
age: {
type: String,
require: true
},
mevki_id: {
type: String,
require: true
},
location_id: [{
type: Mongoose.Schema.Types.ObjectId,
ref: 'locations'
}]
});
var collectionName = 'users';
var User = Mongoose.model(collectionName, userSchema);
return User;
})();
User Controller
function userController() {
var User = require('../models/UserSchema');
this.createUser = function (req, res, next) {
var name = req.body.name;
var surname = req.body.surname;
var tel = req.body.tel;
var age = req.body.age;
var mevki_id = req.body.mevki_id;
var lok_id = req.body.lok_id;
User.create({
name: name,
surname: surname,
tel: tel,
age: age,
mevki_id: mevki_id,
lok_id: lok_id
}, function (err, result) {
if (err) {
console.log(err);
return res.send({
'error': err
});
} else {
return res.send({
'result': result,
'status': 'successfully saved'
});
}
});
};
this.getUser = function (req, res, next) {
User.find()
.populate('lok_id')
.exec(function (err, result) {
if (err) {
console.log(err);
return res.send({
'error': err
});
} else {
return res.send({
'USERS': result
});
}
});
};
return this;
};
module.exports = new UserController();

First, your schema is wrong:
var userSchema = new Mongoose.Schema({
// ...
location_id: { type: [Mongoose.Schema.Types.ObjectId], ref: 'locations' }
})
Second, in your schema the last field name is location_id while in your controller, you change it to lok_id.
So, fix this:
User.create({
// ...
location_id: lok_id
}
and this:
User
.find()
.populate('location_id')
UPDATE
In your json the last field name is location_id, therefore, fix this too:
this.createUser = function (req, res, next) {
// ...
var lok_id = req.body.location_id;
}

Related

find all in mongoose

I have Schema With name score, and that have an iduser: req.session.user._id.
and I have more than one items with same iduser. I wanna to find all the items with the same iduser. and I use the
var users = await storescors16.find({ id }) id = res.session.user._id.
but that show me all the items in score !
My code
//schema
const storescor = new mongoose.Schema({
iduser: String,
level: { type: String, default: null },
day: { type: String, default: null },
date: { type: String, default: null },
time: { type: String, default: null },
objectif: { type: String, default: null }
})
var storescors16 = mongoose.model("storescor", storescor);
//post infos to database
router.post('/control/edite-control', (req, res) => {
console.log(req.session.selectuserid);
var { level, day, date, time, ob } = req.body
var scor = new storescors16({
iduser: req.session.selectuserid,
level: level,
day: day,
date: date,
time: time,
objectif: ob,
})
//read infos from databse
router.get('/result', auth, async(req, res) => {
var id = req.session.user._id
console.log(id);
var user = User.findById(id, (err, docs) => {
if (err)
console.log(err);
else
console.log();
})
var ids = req.session.user._id
var notes = await storescors16.find({ ids })
console.log(notes);
let scor = user.quiz
res.render('./options/result', {
notes: notes,
scor: scor,
title: 'سجل درجات النجم',
name: session.user.name,
email: session.user.email,
})
});
I use nodejs as backend
If you want to find all use findAll function with where.
const users = await storescors16.findAll({ id });
That if I understand you currect.

How do you save to three collections at once?

I'm building my first mean stack app. It's a review site that contains three models: User, Review, and Company.
When I make a review, I want the new review to be saved to the 'review' collection, and for that review to be connected by reference to the company being reviewed and the user who wrote the review. I also want the user to hold a reference to the review, and the company to hold a reference to all the reviews it has. Here are my models:
Review
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const reviewSchema = new Schema ({
companyName: String,
companyId: { type: Schema.Types.ObjectId, ref: 'Company'},
starRating: Number,
subject: String,
commentBody: String,
createdBy: { type: Schema.Types.ObjectId, ref: 'User'},
});
const Review = mongoose.model("Review", reviewSchema);
module.exports = Review;
Company
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const companySchema = new Schema ({
companyName: String,
about: String,
basedIn: String,
materialOrigins: [String],
productRange: [String],
category: String,
reviews: [ {type: Schema.Types.ObjectId, ref: 'Review'} ],
socialRating: Number,
environmentalRating: Number,
priceRange: Number
});
const Company = mongoose.model("Company", companySchema);
module.exports = Company;
User
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const userSchema = new Schema ({
email: String,
firstName: String,
lastName: String,
password: String,
image: Object,
aboutText: String,
reviews: [ { type: Schema.Types.ObjectId, ref: "Review" } ]
// comments: { type: Schema.Types.ObjectId, ref: 'Comment' }
});
const User = mongoose.model("User", userSchema);
module.exports = User;
This is my current route, which currently saves the review to the collection and attaches the user. However, the user doesn't get the review.
route
router.post('/:category/:company', (req, res) => {
var subject = req.body.subject;
var commentBody = req.body.commentBody;
var starRating = req.body.starRating;
var userId = req.body.userId;
if(!subject || !commentBody || !starRating) {
res.status(400).json({ message: "Subject, comment body, and star rating are required." });
return;
}
var newReview = Review({
starRating,
subject,
commentBody,
userId
});
User.findById(userId, {
}, (err, user) => {
if (err) {
return res.send(err);
} else {
console.log("checking out user in route", user);
user.reviews.push(newReview);
user.save();
newReview.save((err, review) => {
if (err) {
return res.status(400).json({ message: err });
} else {
res.status(200).json({ message: 'Review saved', review });
}
});
}
});
I haven't tried adding the company in because I'm trying to do one thing at a time. I've been looking at 'populate', but all of the documentation seems to only use two models at once. Is it possible to do three at once? Or am I overcomplicating this?
Apologies if this is all overcomplicated. I'm fairly new to MongoDB and MEAN stack in general. Thanks for your help.
Ok, I did it, for any people landing on this page wondering the same thing in the future.
Here's my route:
router.post('/:category/:company', (req, res, next) => {
var companyName;
var companyId;
var subject = req.body.subject;
var commentBody = req.body.commentBody;
var starRating = req.body.starRating;
var createdBy = req.body.createdBy;
if(!subject || !commentBody || !starRating) {
res.status(400).json({ message: "Subject, comment body, and star rating are required." });
return;
}
var newReview = Review({
starRating,
subject,
commentBody,
createdBy
});
//I need the companyId and companyInfo for later use in my review save. I'm calling the company with the name I have from my params, and setting the id and name with the received data from Mongo.
Company.findOne({"companyName": req.params.company}, (err, company) => {
if (err) {
return res.status(400).json({ message: err });
} else {
this.companyName = company.companyName;
this.companyId = company.id;
}
});
newReview.save((err, review) => {
//Push the review id to the user
if (err) {
return res.status(400).json({ message: err });
} else { User.findByIdAndUpdate({_id: createdBy },{$push: {reviews: review.id} }, (err) => {
if (err) {
console.log("There was an error pushing review to user");
next(err);
//Push the review id to the company
} else { Company.findOneAndUpdate({ "companyName": req.params.company}, {$push: {reviews: review.id}}, (err, company) => {
if (err) {
console.log("There was an error pushing review to company");
next(err);
} else {
//Updates the review by setting companyId and companyName properties to review for Mongo
Review.update({_id: review.id}, {$set: {companyId: this.companyId, companyName: this.companyName}}, (err, changes) => {
if(err) {
return res.status(400).json({message : err});
} else {
console.log("updating review successfully with company info", changes);
}
});
console.log ("Review successfully saved");
res.json({
review: review,
});
}
});
}
});
}
});
});
If anyone has feedback on how this could be done better/more efficiently, let me know. Cheers.

Packing data with mongoose

I have 3 files with different schema. User has many notebooks and notebooks has many notes. Example of schemas :
UserSchema:
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var User = new Schema({
username: { type: String, require: true, index: { unique: true }, trim: true},
password: { type: String, require: true, select: true },
age: { type: Number, min: 0 },
firstname: String,
secondname: String,
token: String,
role: String,
city: String,
rememberMe: Boolean
});
module.exports = mongoose.model('User', User);
NotebookSchema:
var mongoose = require('mongoose'),
Schema = mongoose.Schema,
Note = require('./note'),
User = require('./user');
var NoteBook = new Schema({
creator: { type:Schema.ObjectId, ref:"User"},
name: String,
description: String
});
NoteBook.methods.getAllNotes = function(cb) {
Note.find({notebook: this}, function(err, noteList){
cb(noteList);
});
};
module.exports = mongoose.model('NoteBook', NoteBook);
NoteSchema:
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var NoteSchema = new Schema({
notebook: { type: Schema.Types.ObjectId, ref: 'NoteBook'},
name: String,
description: String,
content: String
});
module.exports = mongoose.model('Note', NoteSchema);
I get in request userId and I need to pack json all this line of data. User with Notebooks and Notebooks with note in one json. I triyed something like this:
function getTree(req, res) {
var data = [];
User.findOne({_id: req.body.userId}, function(err, user) {
NoteBook.find({creator: user._id}, function(err, notebookList) {
for (var idx in notebookList) {
Note.find({notebok: notebookList[idx]._id}, function(err, noteList) {
var children = [];
for (var noteIdx in noteList) {
children.push({
'text': noteList[idx].name,
'a_attr' : {
'data-node-type': 'note',
'data-node-id': noteList[idx]._id,
},
});
}
data.push({
'text': notebookList[idx].name,
'a_attr' : {
'data-node-type': 'notebook',
'data-node-id': notebookList[idx]._id,
},
'children': children
});
});
}
res.json({ tree: data });
});
});
}
but it doesn't work.
var async = require("async");
function getTree(req, res) {
var data = [];
User.findOne({_id: req.body.userId}, function(err, user) {
NoteBook.find({creator: user._id}, function(err, notebookList) {
async.forEach(notebookList, function(notebook, callback){
Note.find({notebok: notebook._id}, function(err, noteList) {
var children = [];
for (var noteIdx in noteList) {
children.push({
'text': noteList[idx].name,
'a_attr' : {
'data-node-type': 'note',
'data-node-id': noteList[idx]._id,
},
});
}
data.push({
'text': notebookList[idx].name,
'a_attr' : {
'data-node-type': 'notebook',
'data-node-id': notebook._id,
},
'children': children
});
});
}, function(err){
res.json({ tree: data });
});
});
});
}

How to save userId in mongoose hook?

Given yon schema, how do I save userId to createdBy and updatedBy?
This seems like it should be an easy use case. How do I do it?
I'm not sure how to get userId from req.user.id to the model before being written.
// graph.model.js
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var schema = new Schema({
title: String,
createdAt: Date,
createdBy: String,
updatedAt: Date,
updatedBy: String,
});
// This could be anything
schema.pre('save', function (next) {
- if (!this.createdAt) {
this.createdAt = this.updatedAt = new Date;
this.createdBy = this.updatedBy = userId;
} else if (this.isModified()) {
this.updatedAt = new Date;
this.updatedBy = userId;
}
next();
});
Here's the controller code if you're interested:
var Graph = require('./graph.model');
// Creates a new Graph in the DB.
exports.create = function(req, res) {
Graph.create(req.body, function(err, thing) {
if(err) { return handleError(res, err); }
return res.status(201).json(thing);
});
};
// Updates an existing thing in the DB.
exports.update = function(req, res) {
if(req.body._id) { delete req.body._id; }
Graph.findById(req.params.id, function (err, thing) {
if (err) { return handleError(res, err); }
if(!thing) { return res.send(404); }
var updated = _.merge(thing, req.body);
updated.save(function (err) {
if (err) { return handleError(res, err); }
return res.json(thing);
});
});
};
The following is just another way of saving userId.
Sample model with createdBy, updatedBy, createdAt, updatedAt fields:
import mongoose from 'mongoose';
const SupplierSchema = new mongoose.Schema(
{
name: {
type: String,
},
createdBy: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
},
updatedBy: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
},
},
{
timestamps: {
createdAt: true,
updatedAt: true,
},
},
);
export default mongoose.model('Supplier', SupplierSchema);
Note that in mongoose starting from version ^4.13.17 you can simply specify timestamps createdAt, updatedAt directly in the schema.
https://mongoosejs.com/docs/4.x/docs/guide.html#timestamps
Then in supplier controller assign req.user._id to the fields createdBy, updatedBy:
import mongoose from 'mongoose';
import { Supplier } from '../models';
exports.create = async (req, res) => {
const supplierToCreate = new Supplier({
_id: new mongoose.Types.ObjectId(),
name: req.body.name,
createdBy: req.user._id,
updatedBy: req.user._id,
});
return supplierToCreate
.save()
.then(() =>
res.status(201).json({
message: 'New supplier is created successfully.',
}),
)
.catch(errSaving => res.status(500).json({ error: errSaving }));
};
You can't access req object inside of mongoose hook.
I think, you should define virtual field with a smart setter instead:
schema.virtual('modifiedBy').set(function (userId) {
if (this.isNew()) {
this.createdAt = this.updatedAt = new Date;
this.createdBy = this.updatedBy = userId;
} else {
this.updatedAt = new Date;
this.updatedBy = userId;
}
});
Now all you have to do is to set modifiedBy field with correct userId value in your controller:
var updated = _.merge(thing, req.body, {
modifiedBy: req.user.id
});

Schema declaration and subdocument

Can you tell me what i'm doing wrong ?
var ObjectId = Schema.Types.ObjectId;
var ProductSchema = new Schema({
name: { type: String, required: true },
price: { type: Number, required: true },
category : { type: String, required: true }
});
var OrderSchema = new Schema({
products: [{
product: {type: ObjectId, ref: 'Product'},
quantity: {type: Number}
}],
status: { type: String, required: true }
});
Product = mongoose.model('Product', ProductSchema);
Order = rmongoose.model('Order', OrderSchema);
OrderSchema.statics.addOrder = function (data, cb) {
// data: array of products ID
var newOrder = new Order();
data.data.forEach(function(element, index, array) {
Product.findOne({ '_id': element.id }, function (err, product) {
if (err) return handleError(err);
newOrder.products.push({product: product, quantity: element.quantity});
})
});
newOrder.status = 'waiting';
newOrder.save(function (err, order) {
if (err) cb(err, false);
console.log(order);
var response = json.stringify({
event: 'addOrder',
success: true,
data: order.id
});
cb(false, response);
});
}
When i add an order products, array is always empty but i have no error. Maybe it's the wrong to do what i want.
Data send by the client are good and the foreach and findOne work well but push seems doing nothing.
If there is no solution maybe you can try to help me to find another solution.
Thanks :)
That's because you need to wait for all the products to be found.
Try this (untested):
OrderSchema.statics.addOrder = function (data, cb) {
// data: array of products ID
var newOrder = new Order();
var productIds = [];
var quantity = [];
data.data.forEach(function(element, index, array) {
productIds.push(element.id);
quantity.push(element.quantity);
});
Product.find({ '_id' : { $in: productIds} }, function(err, products) {
if (err) return handleError(err);
products.forEach(function(product, index) {
newOrder.products.push({product: product, quantity: quantity[index]});
});
newOrder.status = 'waiting';
newOrder.save(function (err, order) {
if (err) cb(err, false);
console.log(order);
var response = json.stringify({
event: 'addOrder',
success: true,
data: order.id
});
cb(false, response);
});
});
});

Resources