Mongoose create method ignores variable, but not hard coded data - javascript

Can someone lead me in the right direction? I'ven been stuck on this a few days. I'm using Express and Mongoose. Here is my controller,
module.exports.addPoll = function(req,res) {
var optionsArray = [];
var row = [];
req.body.option1.forEach( function(value) {
optionsArray.push('{"v":"' + value + '"},{"v":0}');
});
var beg = '{"c":[';
var end = ']}';
var whole = beg.concat(optionsArray, end);
Pol.create({
cols: [{label: "options", type: "string"}, {label: "quantity", type:
"number"}],
rows: whole,
title: req.body.heading
}, function(err, poll) {
if (err) {
sendJSONresponse(res, 400, err);
} else {
sendJSONresponse(res, 201, poll);
console.log(whole);
}
});
}
When i create the document the rows property is empty. It ignores the variable that has the data and looks like this.
{"__v":0,"rows":{"c":[]},"title":"What is tomorrow","_id":"59826915c7a0186940e8431c","cols":[{"label":"options","type":"string"},{"label":"quantity","type":"number"}]}
Here is what it looks like when it logs and if replace the variable withi this, it works perfectly fine. I don't get it.
[{"c":[{"v":"Monday"},{"v":"0"},{"v":"Tuesday"},{"v":"0"}]}]
Here is my schema.
var rowsSchema = new mongoose.Schema({
c: [{
v: {
type: String,
required: true
},
_id:false
},
{
v:{
type:Number,
required: true
},
_id:false
}],
_id: false
})
var pollSchema = new mongoose.Schema({
cols: [{
label: {
type: String,
required: true
},
type: {
type: String,
required: true
},
_id: false
},
{
label: {
type: String,
required: true
},
type: {
type: String,
required: true
},
_id:false
}],
rows: rowsSchema,
title: {type: String, required:true, _id:false}
})

Related

Mongoose populate() is returning an empty array

I am trying to use mongoose populate function but in response I am getting empty array. I know there are several questions talking about the same subject but none worked for my case.
My objective is to populate my Order document.
This is how my schemas are organized:
Menu.js
const mongoose = require("mongoose");
const { Schema } = mongoose;
const Food = require("./Food");
const Drink = require("./Drink");
const MenuSchema = new Schema({
code: {
type: mongoose.ObjectId,
required: true,
unique: true,
},
name: {
type: String,
required: true,
},
food: {
type: [Food.schema],
required: false,
},
drinks: {
type: [Drink.schema],
required: false,
},
type: {
type: String,
},
createdAt: {
type: Date,
default: Date.now,
},
});
module.exports = mongoose.model("Menu", MenuSchema);
Note: Im using Food.schema and Drink.schema inside my Arrays instead of making a ref. Im storing the Food and Drink models inside of the Menu model
Food.js
const mongoose = require("mongoose");
const { Schema } = mongoose;
const FoodSchema = new Schema({
code: {
type: mongoose.ObjectId,
required: true,
unique: true,
},
description: {
type: String,
required: true,
},
ingredients: {
type: [],
required: false,
default: [],
},
stock: {
type: Number,
required: true,
},
type: {
type: String,
enum: ["starter", "main", "dessert"],
required: true,
},
price: {
type: Number,
required: true,
},
createdAt: {
type: Date,
default: Date.now,
},
});
module.exports = mongoose.model("Food", FoodSchema);
Drink.js
const mongoose = require("mongoose");
const { Schema } = mongoose;
const DrinkSchema = new Schema({
code: {
type: mongoose.ObjectId,
required: true,
unique: true,
},
description: {
type: String,
required: true,
},
stock: {
type: Number,
required: true,
},
price: {
type: Number,
required: true,
},
createdAt: {
type: Date,
default: Date.now,
},
});
module.exports = mongoose.model("Drink", DrinkSchema);
Order.js
const mongoose = require("mongoose");
const { Schema } = mongoose;
const OrderSchema = new Schema({
code: {
type: mongoose.ObjectId,
required: true,
unique: true,
},
type: {
type: String,
required: true,
enum: ["restaurant", "takeaway", "delivery"],
},
food: {
type: [{ type: mongoose.ObjectId, ref: "Food" }],
required: false,
default: [],
},
drinks: {
type: [{ type: mongoose.ObjectId, ref: "Drink" }],
required: false,
default: [],
},
orderValue: Number,
client_id: {
type: mongoose.ObjectId,
ref: "Client",
required: false,
},
createdAt: {
type: Date,
default: Date.now,
},
});
module.exports = mongoose.model("Order", OrderSchema);
This is the controller where I'm trying to make my populate work. Whenever I remove the populate method I get the _id references for the Food and Drink arrays.
TableController.js
exports.getOrderFromTable = async (req, res) => {
const { code, tableCode } = req.params;
try {
const foundRestaurant = await Restaurant.findOne({ code: code });
const foundTable = foundRestaurant.tables.filter(
(table) => table.code == tableCode
);
console.log(foundTable[0].order_id);
const foundOrder = await Order.findOne({
_id: foundTable[0].order_id,
})
.populate("food")
.populate("drinks");
res.send(foundOrder);
} catch (err) {
res.json({ message: err });
}
};
And this is what the mongoose debugger returns when I run the controller:
Mongoose: restaurants.findOne({ code: new ObjectId("62a60dcb9fe25d276815675c") }, { projection: {} })
new ObjectId("62a60ece9fe25d27681567b7")
Mongoose: orders.findOne({ _id: new ObjectId("62a60ece9fe25d27681567b7") }, { projection: {} })
Mongoose: foods.find({ _id: { '$in': [ new ObjectId("62a60e039fe25d276815677d"), new ObjectId("62a60e169fe25d2768156785") ], [Symbol(mongoose#trustedSymbol)]: true }}, { skip: undefined, limit: undefined, perDocumentLimit: undefined, projection: {}})
Mongoose: drinks.find({ _id: { '$in': [ new ObjectId("62a60e259fe25d276815678d"), new ObjectId("62a60e3c9fe25d276815679c") ], [Symbol(mongoose#trustedSymbol)]: true }}, { skip: undefined, limit: undefined, perDocumentLimit: undefined, projection: {}})
And finally this is the JSON file I get when I do a GET http request using Postman:
{
"_id": "62a60ece9fe25d27681567b7",
"code": "62a60ece9fe25d27681567b6",
"type": "restaurant",
"food": [],
"drinks": [],
"orderValue": 25,
"createdAt": "2022-06-12T16:05:34.513Z",
"__v": 0
}
Thank you for any help. I've been really struggling with this method.

Mongoose: Check if value exists in string array

I am querying to get all articles that have a specific source name and category.
I have an article schema that looks like below.
The issue I'm facing is that, it fetches the articles with the correct source name, but it doesn't fetch for the right category. For example, if source is "cnn" and category is "sports", it fetches all articles from CNN correctly, but not with correct categories (the articles may have a categories of ['politics', 'culture'] with no sports)
const article_schema = new mongoose.Schema({
title: {
type: String,
required: true
},
thumbnail_url: {
type: String,
required: true
},
summary: {
type: String,
required: true
},
text: {
type: String,
required: true
},
link: {
type: String,
required: true
},
publish_date: {
type: String,
required: true
},
source: {
name: {
type: String,
required: true
},
name_slug: {
type: String,
required: true
},
link: {
type: String,
required: true
},
display_picture_url: {
type: String,
required: true
},
biography: {
type: String,
required: true
},
tags: {
type: [String],
required: true
},
rssFeeds: [{
url: {
type: String,
required: true
},
categories: {
type: [String],
required: true
}
}]
}
});
let getNews = async (req, res) => {
const { sort, filter, current_page, limit, category_slug } = req.body;
let articles = await Article.findOne({ 'source.name_slug': filter, categories: category_slug });
res.setHeader('Content-Type', 'application/json');
res.status(200).send({ articles });
}

Async Await inside for loop?

Im struggling with this. I have in my db Profile{name: string, table:0}, and im using a for loop to asign the number of the table to the different users, but this is not working. The for loop works fine if i checked in the console, but in the postman request, is not working.
When i filter by table number from the database, there are more than 5 results per table. And in somecases, there are irregular, like, table 1: 8 users, table 2: 5 users, so on...
const ProfileSchema = new Schema(
{
name: {
type: String,
required: true,
},
password: {
type: String,
required: true,
},
moderator: {
type: Boolean,
default: false,
},
email: {
type: String,
required: true,
},
country: {
type: String,
required: true,
},
institution: {
type: String,
/* required: true */
},
score: {
type: [Number],
default: [],
},
active: {
type: Boolean,
required: true,
default: false,
},
img: String,
meetLink: String,
table: {
type: Number,
default: 0,
},
group: Number,
},
routes/index.js
router.put('/asignTable', async (req, res) => {
let users = await Profile.find()
shuffle(users)
asignTable(users)
res.send(users)
routes/utils.js
async function asignTable(users) {
var contador = 0
let numTable = 1
filter = {}
for (const user of users) {
const filter = { name: user.name }
const update = { table: numTable }
if (contador == 5) {
contador = 0
numTable++
console.log(`desde el if ${contador}`)
} else if (contador < 5) {
await Profile.findOneAndUpdate(filter, update).then(contador++)
console.log(`desde el elseif contador:${contador} numtable:${numTable}`)
}
}
}
})

Still getting "Schema is not a constructor", despite properly importing and exporting my Schema

Here is my code. I have a review schema in a separate file called "review.js".
const express = require('express');
const mongoose = require('mongoose');
const User = require('../model/user');
require('mongoose-currency').loadType(mongoose);
const Currency = mongoose.Types.Currency;
const Schema = mongoose.Schema;
let reviewSchema = new Schema();
reviewSchema.add({
rating: {
type: Number,
min: 1,
max: 5,
defualt: 0
},
howEasyToMake: {
type: Number,
required: true,
min: 1,
max: 5
},
howGoodTaste: {
type: Number,
required: true,
min: 1,
max: 5,
},
wouldMakeAgain: {
type: Number,
required: true,
min: 1,
max: 5,
},
comment: {
type: String,
default: ""
},
postedBy: {
type: String,
required: true,
index: true
},
reviewOf: {
type: String,
required: true,
index: true
},
postersCreationDate: {
type: Number,
required: true
},
chefsCreationDate: {
type: Number,
required: true
},
chefsId: {
type: String,
required: true
}
});
module.exports.reviewSchema = reviewSchema;
I have another file called recipe.js, where I import reviewSchema and use it as an embedded schema for my Recipe model schema.
const express = require('express');
const mongoose = require('mongoose');
const User = require('../model/user');
require('mongoose-currency').loadType(mongoose);
const Currency = mongoose.Types.Currency;
const Schema = mongoose.Schema;
const reviewSchema = require('../model/review').reviewSchema;
let recipeSchema = new Schema({
name: {
type: String,
required: true
},
description: {
type: String,
},
steps: {
type: String,
required: true,
},
ingredients: {
type: Array,
default: ['1', '2', '3', '4']
},
category: {
type: String,
required: true,
index: true
},
postedBy: {
type: String,
required: true,
},
reviewsOfRecipe: [reviewSchema],
numberOfRatings: {
type: Number,
default: 0
},
totalAddedRatings: {
type: Number,
default: 0
},
reviewAverage: {
type: Number,
default: undefined
},
postersCreationDate: {
type: Number,
index: true
},
likedBy: {
type: Array
},
reviewedBy: {
type: Array
}
});
recipeSchema.methods.updateReviewAverage = function(){
let recipe = this;
this.reviewAverage = this.totalAddedRatings / this.numberOfRatings;
};
let Recipe = mongoose.model('Recipe', recipeSchema);
module.exports = Recipe;
I have another file called recipeRouter.js where I use reviewSchema to construct a review to then later insert it into the embedded reviewsOfRecipes array in my Recipe document. In my recipRouter.js file, every time my code tries to do this....
Recipe.findOne({name: req.params.name}).then((recipe) => {
let review_ = new reviewSchema({
comment: req.body.comment
rating: req.body.score
});
recipe.reviewsOfRecipe.push(review_);
})
...I get this error.
TypeError: reviewSchema is not a constructor
Previously, when I ran into this problem, I had the reviewSchema in the same file as my Recipe model schema. Since then, I split the two into each having their own file. And I made sure to properly export module.exports.reviewSchema = reviewSchema; in my review.js file, and made sure to have const reviewSchema = require('../model/review').reviewSchema; in both my recipe.js and recipeRouter.js files. Yet still this issue still comes up/ I would greatly appreciate it if someone could point out what may be the issue.
You have to export reviewSchema like you did to the other schema (using mongoose.model):
module.exports.reviewSchema = mongoose.model('Review', reviewSchema);

Manipulating Mongoose/MongoDB Array using Node.js

I've noticed there's little documentation and info about how I should manipulate an array of objects using Mongoosejs.
I have the following model/Schema for an User:
'use strict';
/**
* Module Dependencies
*/
var bcrypt = require('bcrypt-nodejs');
var crypto = require('crypto');
var mongoose = require('mongoose');
/**
* Custom types
*/
var ObjectId = mongoose.Schema.Types.ObjectId;
var userSchema = new mongoose.Schema({
email: { type: String, unique: true, index: true },
password: { type: String },
type: { type: String, default: 'user' },
facebook: { type: String, unique: true, sparse: true },
twitter: { type: String, unique: true, sparse: true },
google: { type: String, unique: true, sparse: true },
github: { type: String, unique: true, sparse: true },
tokens: Array,
profile: {
name: { type: String, default: '' },
gender: { type: String, default: '' },
location: { type: String, default: '' },
website: { type: String, default: '' },
picture: { type: String, default: '' },
phone: {
work: { type: String, default: '' },
home: { type: String, default: '' },
mobile: { type: String, default: '' }
}
},
activity: {
date_established: { type: Date, default: Date.now },
last_logon: { type: Date, default: Date.now },
last_updated: { type: Date }
},
resetPasswordToken: { type: String },
resetPasswordExpires: { type: Date },
verified: { type: Boolean, default: true },
verifyToken: { type: String },
enhancedSecurity: {
enabled: { type: Boolean, default: false },
type: { type: String }, // sms or totp
token: { type: String },
period: { type: Number },
sms: { type: String },
smsExpires: { type: Date }
},
friends: [{
friend: { type: ObjectId, ref: 'User' },
verified: { type: Boolean, default: false }
}]
});
/* (...) some functions that aren't necessary to be shown here */
module.exports = mongoose.model('User', userSchema);
So as you can check I defined Friends inside User like this:
friends: [{
friend: { type: ObjectId, ref: 'User' },
verified: { type: Boolean, default: false }
}]
Now the question is how can I add, edit and delete this array in a Node.js script?
BOTTOMLINE: How can I manipulate arrays that are inside MongoDB Schemas, using Node.js and Mongoose.js? Do I always have to create a Schema function or can I access it directly?
EDIT (13/07/2014): So far I've created a HTTP GET that gives me the array like this:
app.get('/workspace/friends/:userid', passportConf.isAuthenticated, function (req, res) {
User.find({_id: req.params.userid}, function (err, items) {
if (err) {
return (err, null);
}
console.log(items[0].friends);
res.json(items[0].friends);
});
});
But this only returns an array of friendIds, but what if I want to create some sort of '/workspace/friends/:userid/del/:friendid' POST, or add POST. I can't seem to figure out how I can get this done.
You can do something like following
app.get('/workspace/friends/:userid/delete/:friendId', passportConf.isAuthenticated, function (req, res) {
User.findOne({_id: req.params.userid}, function (err, user) {
if (err) {
return (err, null);
}
for (var i = 0; i < user.friends.length; i++) {
if (user.friends[i]._id === req.params.friendId) {
user.friends = user.friends.splice(i,1)
}
}
user.save(function(err, user, numAffected){
if (!err )res.json(user)
res.send('error, couldn\'t save: %s', err)
})
});
});
What it says in mongoose docs is that
"The callback will receive three parameters, err if an error occurred, [model] which is the saved [model], and numberAffected which will be 1 when the document was found and updated in the database, otherwise 0.
The fn callback is optional. If no fn is passed and validation fails, the validation error will be emitted on the connection used to create this model."
If you need to manipulate arrays, you should convert these in objects before.
User.findOne({_id: req.params.userid}, function (err, user) {
if (err) {
return (err, null);
}
var user = user.toObject();
//... your code, an example =>
delete user.friends;
res.json(user);
});
Regards, Nicholls

Categories

Resources