how do I populate a document mongoose or save refs - node.js

I have a questions collection and I have a store model. I want the questions field in the Store model to be to be the array of object ids from the questions collection. so I could use populate later. when I do app.get in the future it should show me a doc with the store info and all the questions.
var Schema = mongoose.Schema;
var storeSchema = Schema({
name : {type : String},
industry : {type : String},
questions :[{type : Schema.Types.ObjectId, ref : "Questions" }]
})
var questionsSchema = Schema({
question : {type :String}
})
var store = mongoose.model("Store", storeSchema);
var questions = mongoose.model("Questions", questionsSchema)
// questions.create({question: "question2"}, function(err,q){
// console.log("create: " , q)
// })
//something like this
questions.find({}, function(err, doc){
store.create({name : "store 1", industry : "industry 1" , questions : /*get the _ids from the question collection*/ {$push : doc.question}})
})
> db.questions.find().pretty()
{
"_id" : ObjectId("574534a289763c004643fa08"),
"question" : "question1",
"__v" : 0
}
{
"_id" : ObjectId("574534acc90f3f2c0c3d529b"),
"question" : "question2",
"__v" : 0
}
>

Population is the process of automatically replacing the specified paths in the document with document(s) from other collection(s). We may populate a single document, multiple documents, plain object, multiple plain objects, or all objects returned from a query.
var question = new Questions();
question.save(function(err) {
var store = new Store({
name:'sample',
industry:'tech',
questions: [question._id],
});
store.save(function(err){
//do whatever you would like, post creation of store.
});
});
Store.find(...).exec(function(err, stores) {
Questions.populate(stores, function(err, storesPostPopulate) {
// Now you have Stores populated with all the questions.
})
});
Since questions field in question schema is an array, you can always push another question id to it.
See mongoose populate
See mongoose Model populate

Related

Mongoose model schema referencing not working

Basically I have 3 mongoose models(user,product,cart).I have tried referencing cart model with user model.I've the used populate method in mongoose to populate the referenced property in the model.But it is not working and I'm getting an empty cart array after adding a product to the cart like this on consoling.
{
"_id": "5a0b2dcf726753258002273d",
"password": "12345",
"securityQuestion": "What is your Nick Name?",
"securityAnswer": "rj1",
"__v": 0,
"cart": [], // empty cart here
"mobileNumber": 1234567890,
"email": "rahul#gmail.com",
"lastName": "jhawar",
"firstName": "rahul",
"userName": "rj"
}
I also wanted to know whether my referencing of models are done correctly(I mean the relationship).
I'm new to this concept.Please help me out.
//Cart.js
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var cartSchema = new Schema({
productName : {type:String,default:''},
productCategory : {type:String,default:''},
productDescription : {type:String,default:''},
productPrice : {type:String,default:''},
sellerName : {type:String,default:''},
});
module.exports=mongoose.model('Cart',cartSchema);
//User.js
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var userSchema = new Schema({
userName : {type:String,default:'',required:true},
firstName : {type:String,default:''},
lastName : {type:String,default:''},
email : {type:String,default:''},
mobileNumber : {type:Number,default:''},
password : {type:String},
securityQuestion : {type:String},
securityAnswer : {type:String},
cart : [{
type: Schema.Types.ObjectId,
ref:'Cart'
}]
});
module.exports=mongoose.model('User',userSchema);
///Routes///
const cartRouter = express.Router();
const cartModel = mongoose.model('Cart');
const userModel = mongoose.model('User');
const productModel = mongoose.model('Product');
cartRouter.get('/addtocart/:id',auth.checkLogin,(req,res)=>{
productModel.findOne({'_id':req.params.id},(err,foundProduct)=>{
if(!err){
const newCartProduct = new cartModel({
productName : foundProduct.productName,
productCategory : foundProduct.productCategory,
productDescription : foundProduct.productDescription,
productPrice : foundProduct.productPrice,
sellerName : foundProduct.sellerName
});
newCartProduct.save((err)=>{
if(!err){
userModel.findOne({'_id':req.session.user._id}).populate('cart')
. exec((err,cartproduct)=>{
console.log(JSON.stringify(cartproduct, null, "\t"));
});
console.log('New Product added to cart');
res.redirect('/users/cart_products');
}
});
});
});
You've correctly set up the relationship between the user and the cart models in that the user potentially holds a reference to a number of cart models.
However, when you save the cart, you aren't actually updating the cart array/property of the user. You have to both save your newCartProduct and you also have to push the resultant id into the cart array and then save your user model. If you don't do this the populate method isn't going to work, since it has nothing to populate.
Here's an example of how you might use findByIdandUpdate to update the user with the new cart item.
cartRouter.get('/addtocart/:id',auth.checkLogin,(req,res)=>{
productModel.findOne({'_id':req.params.id},(err,foundProduct)=>{
if(!err){
const newCartProduct = new cartModel({
productName : foundProduct.productName,
productCategory : foundProduct.productCategory,
productDescription : foundProduct.productDescription,
productPrice : foundProduct.productPrice,
sellerName : foundProduct.sellerName
});
newCartProduct.save((err, o)=>{
if(!err){
userModel.findByIdAndUpdate(req.session.user._id,
{$push: {"cart": o._id}},
{safe: true, new : true})
.populate('cart')
.exec((err, model) => {
console.log(model); //This will have the cart array filled in
});
});
});
Other choices would be either to reverse the relationship, to hang the reference to the user from the cart, or to use an embedded subdocument:
cart: [Cart]
If you never need to access cart entries outside of the context of a single user (if you never need aggregate information across users), then it's probably the right thing to do.
Your approach maybe right for your use cases, but then you have to manually maintain both sides of the relationship when items are added and removed from the cart.

How to push array elements to an array if _id of documents already exists and create new document if _id doesn't exist?

I am using Node.js, mongoose, mongodb, express and angular.
I am saving replies for a survey in a mongoose model. Many people will submit replies for a particular survey. When the first person submits a reply for a survey, I want to create a new document for that survey. When the second, third.... so on people submit replies for the same survey, I want to add array elements only to the replies array in the following schema.
And when the first person submits a reply for a new survey I want to create a new document for the new survey. How can I do this in mongoose?
I found similar question in Mongoose.js: how to implement create or update?. But, here I want to push the new replies to the next array index of replies[] if the _id is found, else create a new document
mongoose model:
var mongoose = require("mongoose");
var Schema = mongoose.Schema;
var MCQReplySchema = new Schema({
_id : String,
surveyname: String,
replies :[{
replierId : String,
answers : [{
questionId : String,
answer : String
}]
}]
});
module.exports=mongoose.model('MCQReply',MCQReplySchema);
Saving data to database:
router.post("/saveMCQAnswer", function(req, res) {
new MCQReply({
_id : '123',
surveyname: 'sample',
replies :[{
replierId : 'R001',
answers : [{
questionId : 'A001',
answer : 'answer'
}]
}]
}).save(function(err, doc){
if(err) res.json(err);
else
req.flash('success_msg', 'User registered to Database');
res.redirect("/");
});
});
pseudo untested code.
MCQReply.findOne({_id : the id}, function(err,doc){
if(err) console.log(err);
// if the survey isn't there `doc` will be null then do your save
if(!doc){
new MCQReply({
_id : '123',
surveyname: 'sample',
replies :[{
replierId : 'R001',
answers : [{
questionId : 'A001',
answer : 'answer'
}]
}]
}).save(function(err, doc){
if(err) res.json(err);
else
req.flash('success_msg', 'User registered to Database');
res.redirect("/");
});
}else(doc){
//you get mongoose document
doc.replies.push({replierId : "R001", answer : [{questionId : "A001" ... whatever else you want}]})
//dont forget to save
doc.save(do error check)
}
})
Don't know if this will work but if your having trouble just saving the _id try this for Schema()
var MCQReplySchema = new Schema({
_id : String,
surveyname: String,
replies :[{
replierId : String,
answers : [{
questionId : String,
answer : String
}]
}]
}, {strict : false});
if {strict :false} doesn't work
try {strict : false, _id :false} or just _id : false

How do I perform a find query in Mongoose?

i have a collection of Ebooks data in mongodb like
{
"_id" : ObjectId("58b56fe19585b10cd42981d8"),
"cover_path" : "D:\\Ebooks\\uploads\\ebooks\\cover\\1488285665748-img1-700x400.jpg",
"path" : "D:\\Ebooks\\uploads\\ebooks\\pdf\\1488285665257-Webservices Natraz.pdf",
"description" : "ebook",
"title" : "book name",
"tag" : [
"Hindi",
"Other"
],
"__v" : NumberInt(0)
}
Now i want to search something if keyword is little bit match from "title:" then show all related books object.
My Mongoose schema is :-
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var EbookSchema = new Schema({
title: {type:String},
description: {type:String},
path: {type:String,required:true},
cover_path: {type:String,required:true},
tag: [{ type: String }]
});
module.exports = mongoose.model('Ebook', EbookSchema);
I try :-
app.get('/ebook?search=',function(req,res){
var search_key = req.param('search');
Ebook.find(title:'search',function(err, ebooks) {
if (err)
res.send(err);
res.json(ebooks);
});
});
but i found null how can i do ? i only want when i search a little-bit keyword i found all related object .
Try wrapping your query in curlies, Mongoose expects an object as the query.
app.get('/ebook?search=',function(req,res){
var search_key = req.param('search');
Ebook.find({title: search_key})
.then(ebooks => res.json(ebooks))
.catch(err => res.status(404).json({ success: false }));
});

Updating a Record in Mongo After Retrieving Its ID From Another Record

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

Data model reference using ObjectID in Mongoose

I have two mongoose models users and requests. One user can have multiple requests. To link these two data models, I am referencing the objectID of the user in the Request model. However when I am trying to fetch all the requests for a particular user ID, I don't get any result.
Users
var UserSchema = new Schema({
name: String,
username: String
});
module.exports = mongoose.model('User', UserSchema);
Requests
var RequestSchema = new Schema({
type: String,
user_id: { type : mongoose.Schema.Types.ObjectId, ref: 'User'}
});
module.exports = mongoose.model('Request', RequestSchema);
Below is the sample code which fetches the requests based on the User ID passed in the URL
exports.getRequests = function (req, res, next) {
var userId = req.params.id;
console.log('USER ID'+userId);
Request.findOne({'user_id': 'kenan'}, function (err, request) {
if (err) return next(err);
if (!requests){
console.log('NO REQUEST FOUND');
return res.send(401);
}
res.json(request);
});
};
I know I am using findOne which will return me a single resource. However this is failing and I am not getting any result. I have in my DB the data populated. Below is the URL for fetching the requests.
http://localhost:9000/api/V1/users/547ee1e82e47bb982e36e433/requests
Please help suggest as to what I am doing wrong over here.
Thanks
You need to populate the references to the users once you do a find().
Once you find all the requests, you need to resolve the references to
the users. Use populate to resolve the references.
After resolving, filter the requests based on the name that you
are searching for.
Updated Code:
Request
.find().populate({'path':'user_id',match:{'name':'kenan'}})
.exec(function (err, resp) {
var result = resp.filter(function(i){
return i.user_id != null;
});
console.log(result);
})
OK, the above answer is correct and thanks for your response. I incorrectly populated my Requests collection. This is just for every one's else knowledge. When you have a Object ID reference as one of the fields in the collection then make sure that you are inserting the ObjectID object instead of just the numerical value.
Wrong
{ "_id" : ObjectId("54803ae43b73bd8428269da3"), "user_id" : "547ee1e82e
47bb982e36e433", "name" : "Test", "service_type" : "test", "version" : "10"
, "environment" : "test", "status" : "OK", "__v" : 0 }
Correct
{ "_id" : ObjectId("54803ae43b73bd8428269da3"), "user_id" : ObjectId("547ee1e82e
47bb982e36e433"), "name" : "test", "service_type" : "test", "version" : "10"
, "environment" : "test", "status" : "OK", "__v" : 0 }

Resources