Pushing object to triple nested array in Mongoose - javascript

I am trying to figure out how to access and push an object into a triple nested array while using mongoose.
My idea is to divide a blog post into an array of chapters, where each has their own array of pages. Each page will have a title, image and body.
Story schema (parent document)
const mongoose = require('mongoose')
const pageSchema = require('./pageModel')
const storySchema = mongoose.Schema({
storyTitle: {
type: String,
required: [true, 'Title required.']
},
storyAuthor: {
type: String,
required: [true, 'Author required.']
},
storyImage: {
type: String,
required: true,
},
chapters: [{
chapterTitle: {
type: String,
//required: [true, 'Title required.']
},
chapterSummary: {
type: String,
// required: [true, 'Summary required.']
},
pages: [pageSchema]
}]
})
module.exports = mongoose.model('Story', storySchema)
the Page Schema
const mongoose = require('mongoose')
const pageSchema = mongoose.Schema({
pageTitle: {
type: String,
required: [true, 'Title required.']
},
pageBody: {
type: String,
},
pageImage: {
type: String,
}
})
module.exports = pageSchema;
Simple ops
const mongoose = require('mongoose')
const Story = require('./storyModel')
const Page = require('./pageModel')
const test = new Story({
storyTitle: 'Test',
storyAuthor: 'Myself',
storyImage: 'test',
});
console.log(test);
test.chapters.push({
chapterTitle: 'chapter 1',
chapterSummary: 'let us see',
})
const first = {
pageTitle: 'A page',
pageImage: 'image',
pageBody: 'A body'
}
console.log(test)
//test.chapters[0].pages[0].push(page)
test.chapters[0].pages.push(first)
console.log(test)
When I log each step, the parent is correctly made, and I am able to append a chapter to the chapters array. But when I the first object, the change isn't visible.
If I log test.chapters, the pages array shows pages: [ [Object] ]
And if I log test.chapters.pages, I just see 'undefined'.
Any suggestions and critique is appreciated.

Related

MongoDB - how do I deep populate, an already populated field that has a reference to the schema it is in?

So I am having the following problem, I have a comments schema, which has a field called Replies and it is pointing toward the comment schema. The problem is that whenever I try to populate the following schema, everything except for the replies gets populated. Why is that happening, how do I fix it?
Comment Schema:
const {Schema, model} = require('mongoose')
const { ObjectId } = require('mongodb');
const commentSchema = new Schema({
Author:
{
type: ObjectId,
required: true,
ref: 'user'
},
Content:
{
type: String,
required: true
},
Likes:{
type: [ObjectId],
ref: 'user'
},
Replies: [this]
})
let comment = model('comment', commentSchema)
module.exports = comment
And that is how I populate the posts model:
let allPosts = await postModel
.find({})
.populate('Author Comments')
.populate(
(
{
path: 'Comments',
populate:[
{path: 'Author'}
]
},
{
path: 'Comments.Replies',
populate:[
{path: 'Author'}
]
}
)
)
and this is my post model, referenced in the previous code sample:
const {Schema, model} = require('mongoose')
const { ObjectId } = require('mongodb');
const postSchema = new Schema({
Author:
{
type: ObjectId,
required: true,
ref: 'user'
},
Content:
{
type: String,
required: true
},
Shares:{
type: [ObjectId],
ref: 'post'
},
Likes:{
type: [ObjectId],
ref: 'user'
},
Comments:{
type: [ObjectId],
ref: 'comment'
}
})
let post = model('post', postSchema)
module.exports = post

How to query a mongo document using mongoose?

MongoDB documents contain an array of objects and what is the best way to query those documents if I want to find and remove an object from an array with some specific value;
Here is an example of the document schema
const mongoose = require("mongoose");
const LibrarySchema = new mongoose.Schema({
user: {
type: mongoose.Schema.Types.ObjectId,
required: true,
},
books: [
{
type: new mongoose.Schema({
bookName: {
type: String,
required: true,
},
chapterReading: {
type: Number,
default: 1,
required: true,
},
}),
},
],
});
const Library = mongoose.model("Library", LibrarySchema);
exports.Library = Library;
If I want to find and remove a book with some bookName
Use $pull
Example :
Library.update({}, { $pull: { books: { bookName: "Yourbookname" } } })

Mongoose populate nested element inside of multiple arrays

I have the following schema:
const userSchema = new Schema({
...,
categories: [
{
name: {
type: String,
required: true
},
products: [
{
type: mongoose.Types.ObjectId,
required: false,
ref: 'Product'
}
]
}
],
...
}
I want to get all the products a user have.
I have seen more questions about this topic but I don't get it to work.
If you entered your data correctly you can do like this:
let result = await User.findById(id).populate("categories.products").lean()

Adding Array To Mongo via AJAX Call and Mongoose

I'm trying to update a document in a mongo database with information from a form, with all the form going into a field which is an array. At the moment I can't get it to update a document, only create a new one, but more pressingly I can't get the information from the form into the array.
Here is my schema:
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const WorkoutSchema = new Schema({
day: {
type: Date,
default: Date.now
},
exercises: [
{
type: String,
trim: true,
required: "Exercise type is required"
},
{
name: String,
trim: true,
required: "Exercise name is required"
},
{
duration: Number
},
{
weight: Number
},
{
reps: Number
},
{
sets: Number
},
{
duration: Number
},
{
distance: Number
}
]
});
const Workout = mongoose.model("Workout", WorkoutSchema);
module.exports = Workout;
And here is my API route. I've included the results of console.logs below it so you can see the information that is getting passed.
app.put("/api/workouts/:id", (req, res) => {
console.log("api body: " + JSON.stringify(req.body));
console.log("body is " + typeof req.body);
var body = JSON.stringify(req.body);
// body = body.split("{")[1];
// body = body.split("}")[0];
// body = "["+body+"]";
console.log(body);
Workout.create({exercises: `${body}`})
.then(Workout => {
res.json(Workout);
})
.catch(err => {
res.json(err);
});
});
api body: {"type":"resistance","name":"Test Press","weight":100,"sets":5,"reps":6,"duration":10}
body is object
{"type":"resistance","name":"Test Press","weight":100,"sets":5,"reps":6,"duration":10}
In the database I get exercises as an array with one element - the above object - instead of a series of key/value pairs. I've tried a lot of things, but this is as close as I get to what I'm trying to do.
Can anyone see where I've gone wrong?
This turned out to be a basic syntax error which came about because one of my keys was "type". The issue is in the syntax of the exercises array, the model should look like this:
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const WorkoutSchema = new Schema({
day: {
type: Date,
default: Date.now
},
exercises: [{
type: {
type: String,
trim: true,
required: "Exercise type is required"
},
name: {
type: String,
trim: true,
required: "Exercise name is required"
},
duration: {
type: Number,
required: "Duration is required"
},
weight: {
type: Number
},
reps: {
type: Number
},
sets: {
type: Number
},
distance: {
type: Number
}
}]
});
const Workout = mongoose.model("Workout", WorkoutSchema);
module.exports = Workout;

How to validate Array of Objects in Mongoose

I need to validate the array of objects in my schema
Schema:
user: [{
name: String,
Age: String,
Contact: Number
}]
How to validate name, age and contact.
I assume your user array is inside another schema.
Let's say we have a Course model with users like this:
const mongoose = require("mongoose");
const courseSchema = new mongoose.Schema({
name: {
type: String,
required: true
},
users: [
{
name: { type: String, required: [true, "Name is required"] },
age: { type: Number, required: [true, "Age is required"] },
contact: { type: Number, required: [true, "Contact is required"] }
}
]
});
const Course = mongoose.model("Post", courseSchema);
module.exports = Course;
To validate this in a post route you can use mongoose model validateSync method:
const Course = require("../models/course");
router.post("/course", async (req, res) => {
const { name, users } = req.body;
const course = new Course({ name, users });
const validationErrors = course.validateSync();
if (validationErrors) {
res.status(400).send(validationErrors.message);
} else {
const result = await course.save();
res.send(result);
}
});
When we send a requset body without required fields like age and contact:
(you can also transform validationErrors.errors for more useful error messages.)
{
"name": "course 1",
"users": [{"name": "name 1"}, {"name": "name 2", "age": 22, "contact": 2222}]
}
The result will be like this:
Post validation failed: users.0.contact: Contact is required, users.0.age: Age is required
It will be similar to the usual validation but inside an array, you need to make a validator function as so:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
//the custom validation that will get applied to the features attribute.
var notEmpty = function(features){
if(features.length === 0){return false}
else {return true};
}
var CarSchema = new Schema({
name: {
type: String,
required: true,
},
features: [{
type: Schema.ObjectId,
ref: Feature
required: true; //this will prevent a Car model from being saved without a features array.
validate: [notEmpty, 'Please add at least one feature in the features array'] //this adds custom validation through the function check of notEmpty.
}]
});
var FeatureSchema = new Schema({
name: {
type: String,
required: true //this will prevent a Feature model from being saved without a name attribute.
}
});
mongoose.model('Car', CarSchema);
mongoose.model('Feature', FeatureSchema);
By using type key/property:
var breakfastSchema = new Schema({
eggs: {
type: Number,
min: [6, 'Too few eggs'],
max: 12
},
bacon: {
type: Number,
required: [true, 'Why no bacon?']
},
drink: {
type: String,
enum: ['Coffee', 'Tea'],
required: function() {
return this.bacon > 3;
}
}
});

Categories

Resources