find(...).populate is not a function in mongoose - node.js

I am trying to populate two tables in mongoose and node and I receive the error that populate is not a function.
I have search and in the documentation it seems that it does the same as I.
Here the model:
var mongoose = require('mongoose');
var dodleSchema = new mongoose.Schema({
name: String,
productorId: {type: mongoose.Schema.ObjectId, ref: "Productor"},
description: String,
ambassadorId: {type: mongoose.Schema.ObjectId, ref: "Ambassador"},
accepted: { type: Boolean, default: false },
read: { type: Boolean, default: false },
deliveryAddress: {
lat: String,
lng: String
},
createdAt: Date,
products: [
{
primaryImage: String,
images: [],
name: String,
max: Number,
min: Number,
step: Number,
stock: Number,
normalPrice: Number,
doodlePrice: Number,
freeShipping: Boolean,
freeShippingFrom: Number
}
],
endsAt: Date,
packagingType: String,
orders: [
{
name: String,
email: String,
purchases: [
{
productId: String,
quantity: Number
}
]
}
]
});
module.exports = mongoose.model('Doodle', dodleSchema);
And then the find that I use:
router.route('/requests/:id')
.get(function (req, res) {
doodleCollection
.find({
ambassadorId: new mongodb.ObjectID(req.params.id),
read: false
})
.populate('productorId')
.toArray(function (error, results) {
if (error) {
res.json({'error': "Ha habido un error en la extracción de requests"});
return false;
}
var alertNew = false;
for (var i = 0; i < results.length; i++) {
if (results[i].read == false) {
readed = true;
break;
}
}
res.json({
requests: results,
alertNew: alertNew
});
});
});
This is the error that I get:
Error

I found the solution and was pretty easy. Seemed that I was really close yesterday.
I was doing the populate method in a collection doodleCollection and I needed to do it in the model.
Changing the object that makes the find totally worked.
Instead of doodleCollection.find(...) now I call doodleModel.find(...) and populate is working perfect!

I was using following which gives me null as data:-
let PostModel = mongoose.model('Post');
Then I changed it as following and populate method worked:-
let PostModel = require("../model/post.js"); //path to your post model
Make sure you exported Model from your post.js model file like following:-
module.exports = mongoose.model('Post', PostSchema);

Related

How to use mongoose to make changes in two different collections in one nodejs query

In this application, I am trying to update a field value, if it is successful then I want to save into a log collection, however, not all the data are saved in the log collection, I am not sure if I am doing it the right way, would appreciate if someone could help out.
here is the query :
// both models(Log & Inventory are imported)
router.get("/add_product/:id/:num/:quantity/:order", (req, res) => {
var id = req.params.id;
var quantity = req.params.quantity;
var order = req.params.order;
// console.log('id----', id);
var num_mod = req.params.num;
var modified_count = parseInt(num_mod) - parseInt(quantity);
console.log("num_mod----", num_mod);
Inventory.findByIdAndUpdate(id, { quantity: parseInt(num_mod) }, { new: true }, function(
err,
inventory
) {
if (err) {
console.log("err", err);
res.status(500).send(err);
} else {
console.log(inventory.name);
const newLog = new Log({
name: inventory.name,
description: inventory.description,
price: parseInt(inventory.price),
quantity: parseInt(inventory.quantity),
modified_quantity: parseInt(modified_count),
itemDest: order //this is not being saved
});
newLog.save(function(err, Log) {
if (err) {
console.log(err);
} else {
console.log("add log success");
res.send(inventory);
}
});
}
});
});
URL from front end :
// order is a string
here is the Log schema :
const mongoose = require("mongoose");
const LogSchema = new mongoose.Schema(
{
// _id: mongoose.Schema.Types.ObjectId,
name: { type: String, required: true },
description: { type: String, required: true },
price: { type: Number, required: true },
quantity: { type: Number, required: true },
modified_quantity: { type: Number, required: true },
supplier: String,
taxable: Boolean,
itemDest: String
},
{ timestamps: true }
);
// Create model from the schema
const Log = mongoose.model("Log", LogSchema);
// Export model
module.exports = Log;
and here is the inventory schema
const mongoose = require("mongoose");
//create Schema
const InventorySchema = new mongoose.Schema(
{
// _id: mongoose.Schema.Types.ObjectId,
name: { type: String, required: true },
description: { type: String, required: true },
price: { type: Number, required: true },
quantity: { type: Number, required: true },
supplier: String,
taxable: Boolean
},
{ timestamps: true }
);
// Create model from the schema
const Inventory = mongoose.model("Inventory", InventorySchema);
// Export model
module.exports = Inventory;
My issue is with this line "itemDest: order" in the query, I intend to save the value of "order" extracted from "req.params.order" into "itemDest" but it doesn't save.

E11000 duplicate key error with MongoDB/Mongoose

I have a user model schema, a work model schema, and a critique model schema. The relationship between these schema's is a user can submit many works (like blog posts), and can comment/review (which we call critiques) other people's posts (works).
So when a user submits a critique (think of it like a review), this is my post route. I find the work by the id, then create a new critique model object, and pass that to the .create() mongoose function. All goes seemingly well until I hit the foundWork.critiques.push(createdCritique) line. the console log errors out saying:
BulkWriteError: E11000 duplicate key error collection: zapper.critiques index: username_1 dup key: { : null }
Obviously, it is saying that there are two username keys in the objects and they're conflicting with each other, but I'm not familiar enough with this to find the root of the issue and fix it in the mongoose models. The models are below. If anyone could help, that'd be greatly appreciated.
// post route for getting the review
router.post('/:id', isLoggedIn, function(req, res) {
Work.findById(req.params.id, function(err, foundWork) {
if (err) {
console.log(err);
} else {
// create a new critique
var newCritique = new Critique ({
reviewerName: {
id: req.user._id,
username: req.user.username
},
work: {
id: foundWork._id,
title: foundWork.title
},
critique : req.body.critique,
date: Date.now(),
rating: 0
});
// save new critique to db
Critique.create(newCritique, function(err, createdCritique) {
if (err) {
console.log(err)
} else {
console.log("Created critique is ");
console.log(createdCritique);
// push the new critique into array of critiques of the work
foundWork.critiques.push(createdCritique);
// save to db
foundWork.save();
}
});
}
});
User model:
var mongoose = require('mongoose');
var passportLocalMongoose = require('passport-local-mongoose');
var UserSchema = new mongoose.Schema({
firstname: String,
lastname: String,
username: String,
password: String,
email: String,
zip: String,
bio: {
type: String,
default: ''
},
influences: {
type: String,
default: ''
},
favBooks: {
type: String,
default: ''
},
notWriting: {
type: String,
default: ''
},
favHero: {
type: String,
default: ''
},
favVillain: {
type: String,
default: ''
},
works: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'Work'
}
],
critiques: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'Critique'
}
],
friends: [
{
friendId: String,
friendName : String,
friendPic: String
}
],
friendRequests: [
{
sendingFriendId: String,
sendingFriendName : String,
sendingFriendPic: String
}
],
createdDate: {
type: Date,
default: Date.now
},
lastLogin: {
type: Date,
default: Date.now
}
});
UserSchema.plugin(passportLocalMongoose);
module.exports = mongoose.model("User", UserSchema);
Work model:
var mongoose = require('mongoose');
var WorkSchema = new mongoose.Schema({
title: String,
genre: String,
workType: String,
length: Number,
ageRange: String,
author: {
id: {
type: mongoose.Schema.Types.ObjectId,
ref: "User"
},
username: String
},
manuscriptText: String,
critiques: [
{
id: {
type: mongoose.Schema.Types.ObjectId,
ref: "Critique"
}
}
],
ratingNumber: [Number],
ratingSum: {
type: Number,
default: 0
},
date: {
type: Date,
default: Date.now
},
isPublic: {
type: Boolean,
default: true
}
});
module.exports = mongoose.model("Work", WorkSchema);
Critique model:
var mongoose = require('mongoose');
var passportLocalMongoose = require('passport-local-mongoose');
var CritiqueSchema = new mongoose.Schema({
reviewerName: {
id: {
type: mongoose.Schema.Types.ObjectId,
ref: "User"
},
username: String
},
work: {
id: {
type: mongoose.Schema.Types.ObjectId,
ref: "Work"
},
title: String
},
critique: String,
date: {
type: Date,
default: Date.now
},
rating: [Number]
});
CritiqueSchema.plugin(passportLocalMongoose);
module.exports = mongoose.model("Critique", CritiqueSchema);
When you create a unique index in MongoDB, the default behavior is that it will index null values also.
This means if you have a document in your collection with a username of null, you can not add another one with a username of null.
What you need is a sparse index which only indexes actual values (and ignores documents with null for that field).
Check this link It shows how to create a sparse index vs "normal" one in mongoose (index: true, vs spare: true). Most of the time you would want sparse indexes.

Mongoose: utils.populate: invalid path. Expected string. Got typeof 'undefined'

I am not a totally new populate user but now I do not know what's wrong.
Here I need to populate my designerId which is type of ObjectId. Take a look at my route.
ordersAdminRouter.route('/customorder/add')
.post(function(req, res){
body = req.body;
console.log(body);
CustomOrders.create(body, function(err, saved){
if (err) throw err;
Designs.findByIdAndUpdate(saved.designId, {$set: {status: 'Order Sent'}}, {new: true}).exec()
.then(function(updated){
return CustomOrders.findById(saved._id).populate(saved.designId).exec();
})
.then(function(orders){
res.json(orders);
})
.then(undefined, function(err){
console.log(err);
})
});
});
saved._id is working because when I remove the populate, it returns the document that I need without the populated document of course.
Take a look at my schema
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var customOrderSchema = new Schema({
designId: { type: Schema.Types.ObjectId, ref: 'customDesigns' },
size: { type: String },
quantity: { type: Number },
totalPrice: { type: Number },
paymentMode: { type: String },
rcpt_img: { type: String },
refNumber: { type: String }
});
module.exports = mongoose.model('customOrders', customOrderSchema);
Here is my customDesigns schema.
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var customDesignSchema = new Schema({
item_name: { type: String },
price: { type: Number, default: 0 },
img_url_front: { type: String },
img_url_back: { type: String },
designer: { type: Schema.Types.ObjectId, ref: 'users' },
color: { type: String },
designDate: { type: Date, default: Date.now() },
status: { type: String, default: 'For Qoutation' }
});
module.exports = mongoose.model('customDesigns', customDesignSchema);
I need to admit that I am new to promises on mongoose & express and this is my first time doing so. But using populate, i use it more than I can think of. Any suggestions?
return CustomOrders.findById(saved._id).populate('designId').then(.. your code);
By the way, you dont must use .exec() then you want execute your query, .then executes query as well. You can skip .exec()
http://mongoosejs.com/docs/populate.html
http://mongoosejs.com/docs/api.html#query_Query-populate

product is not added to my collection

In my project I have 2 models: Store and product, basically every store can have a number of products, but each product can be related to 1 store, so to build the models I did this:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var lojasSchema = new mongoose.Schema({
email: {
type: String,
unique: true,
required: true
},
nome: {
type: String,
required: true,
unique: true
},
descricao: {
type: String,
default: "No description for this store"
},
telefone:{
type:String,
},
password:
{
type: String, required: true
}
,
img: {
data: Buffer, contentType: String
},
imgNome: {
type: String
},
produtos: [
{ type: mongoose.Schema.ObjectId, ref: 'Produto' }
],
});
module.exports = mongoose.model('Loja', lojasSchema);
my product is like this
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var produtoSchema = mongoose.Schema({
nome:{
type:String, required:true
},
stock:{
type:Number
},
descricao:{
type:String
},
categoria:{
type: String, required:true
},
tamanho:{
type: String, required:true
},
data:{
type: Date, default: Date.now
},
preco:{
type: Number,required:true, default: 0
}
});
module.exports = mongoose.model('Produto',produtoSchema);
as you guys can see I have the reference on the store side, basically what I want is every time I add a product I add that product directly to a store(storeID), so to do that I added this to my store side routes:
//adiciona um produto a uma loja especifica
router.post('/:id/produtos',function(req,res){
Loja.findById(req.params.id,function(err,loja){
if(!loja){
return res.status(404).json({Error:"Loja nao encontrada"});
}
if(JSON.stringify(req.body) == "{}")
{
return res.status(400).json({Error:"Your request is empty"});
}
var produto = new Produto(req.body);
loja.produtos.push(produto);
loja.save(function(err){
if(err){
return res.status(500).json({Error:"Server problem"});
}
res.status(200).json({message: "product added"});
});
})
})
I got 2 problems: when I go to my get products route, I get an empty array, I should get there all the products, I think the product is not getting added in the product's model, the second problem is: every time I add a product to my store, and go to see all my stores with the .populate I just can see an id inside the products array, I should see all the product details, what am I doing wrong?:S
Update you mongoose to 4.8.1 because 4.7.6 is buggy with casting Ids.
then go to your lojas.js and require mongoose at the top.
Replace your code with this
router.post('/:id/produtos',function(req,res){
var queryObject = {_id : mongoose.Types.ObjectId(req.params.id)};
Loja.findById(queryObject,function(err,loja){
console.log(err);
if(!loja){
return res.status(404).json({Error:"Loja nao encontrada"});
}
if(JSON.stringify(req.body) == "{}")
{
return res.status(400).json({Error:"Your request is empty"});
}
var produto = new Produto(req.body);
produto.save(function (err) {
if(err){
return res.status(500).json({Error:"Server Problem"})
}
loja.produtos.push(produto._id);
loja.save(function(err){
if(err){
return res.status(500).json({Error:"Server problem"});
}
res.status(200).json({message: "product added"});
});
});
})
})

Save array of ObjectId in Schema

I have a model called Shop whos schema looks like this:
'use strict';
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var ShopSchema = new Schema({
name: { type: String, required: true },
address: { type: String, required: true },
description: String,
stock: { type: Number, default: 100 },
latitude: { type: Number, required: true },
longitude: { type: Number, required: true },
image: String,
link: String,
tags: [{ type: Schema.ObjectId, ref: 'Tag' }],
createdAt: { type: Date, default: Date.now },
updatedAt: { type: Date, default: Date.now }
});
module.exports = mongoose.model('Shop', ShopSchema);
I want to use the array tags to reference to another model via ObjectId obviously. This set up works fine when I add ids into the property via db.shops.update({...}, {$set: {tags: ...}}) and the ids get set properly. But when I try to do it via the Express.js controller assigned to the model, nothing gets updated and there even is no error message. Here is update function in the controller:
// Updates an existing shop in the DB.
exports.update = function(req, res) {
if(req.body._id) { delete req.body._id; }
Shop.findById(req.params.id, function (err, shop) {
if (err) { return handleError(res, err); }
if(!shop) { return res.send(404); }
var updated = _.merge(shop, req.body);
shop.updatedAt = new Date();
updated.save(function (err) {
if (err) { return handleError(res, err); }
return res.json(200, shop);
});
});
};
This works perfect for any other properties of the Shop model but just not for the tags. I also tried to set the type of the tags to string, but that didn't help.
I guess I am missing something about saving arrays in Mongoose?
It looks like the issue is _.merge() cannot handle merging arrays properly, which is the tags array in your case. A workaround would be adding explicit assignment of tags array after the merge, if it is ok to overwrite the existing tags.
var updated = _.merge(shop, req.body);
if (req.body.tags) {
updated.tags = req.body.tags;
}
Hope this helps.. If the workaround is not sufficient you may visit lodash forums.

Resources