Find Object and Update by pushing to nested Array in MongoDb - node.js

I have created a Mongoose Model which holds nested arrays exercises>history>data. I want to make a put request and push an Object, consisting of the time the data was createdAt as well as an array of the Users data to the history of the exercise that was run. However, the following attempt did not work:
User.findOneAndUpdate(
{ _id: req.user.id, "exercises.title": req.body.exercise_title },
{ $push: { "exercises.$.history": { data: [1,2,3,4,5] } } }
);
My Schema looks as follows:
const mongoose = require('mongoose');
const UserSchema = new mongoose.Schema({
userName:{
type: String,
required: true},
exercises:[{
title:{
type: String,
},
history: [{
createdAt: {
type: Date,
default: Date.now
},
data: []
}]
}]
});
module.exports = mongoose.model('User', UserSchema)
I have no clue why my query is not working

Related

How to create a dynamic nested mongoose document with the same schema on multiple levels

Before everyone tells me I can't call a const before initializing, I do know that.
But I think this is the simplest way to render the concept I have in mind, (where any subdocument within the replies array also has the same schema as the parent, and documents within the replies array of those subdocuments also having the same schema). I would really appreciate anyone's input.
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
var commentSchema = new mongoose.Schema({
content: String,
createdAt: {
type: Date,
default: Date.now
},
score: {
type: Number,
default: 1
},
username: {
type: String,
lowercase: true
},
parent: {
type: Schema.Types.ObjectId,
ref: 'comment'
},
replyingTo: String,
replies: [commentSchema]
});
module.exports = mongoose.model("comment", commentSchema);
Since a const can't be called before initialization, to fix this issue the parent schema should be called on the children array after initialization the code below:
commentSchema.add({ replies: [commentSchema] })
The final result should look like this:
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const commentSchema = new mongoose.Schema({
content: String,
createdAt: {
type: Date,
default: Date.now
},
score: {
type: Number,
default: 1
},
username: {
type: String,
lowercase: true
},
parent: {
type: Schema.Types.ObjectId,
ref: 'comment'
},
replyingTo: String,
});
commentSchema.add({ replies: [commentSchema] })

How to set "capped" after collection is created?

I am attempting to set a capped parameter to my collection within my mongoose.Schema that did not include capped at first.
Any help welcome.
My Schema:
const mongoose = require('mongoose')
var Schema = mongoose.Schema;
var userSchema = new Schema({
name: { type: String, required: true },
email: { type: String },
password: { type: String },
isAdmin: {type: Boolean, default: false},
avatar: { type: String },
joinDate: { type: Date, default: Date.now() },
},{ autoCreate: true, capped : 1024})
userSchema.set('timestamps', true);
const Users = mongoose.model('Users', userSchema)
module.exports = Users;
I get following error:
Error: A non-capped collection exists with the name: users
To use this collection as a capped collection, please first convert it.
Seems like you have already created a users collection in your database. So to convert it into a capped run below command either in mongoshell or robomongo
db.runCommand( { convertToCapped: 'users', size: 1024 } )

MongoDB populate() to dynamically load/migrate data not working

I am building an app in which the user adds and deletes objects (Pic) in an array('pics') after registering, but not sure how to dynamically load or populate('pics') to userSchema to automatically render. The user registers on the app with that array originally empty ('pics' = zero), and will create or delete those objects thereafter when logged in.
Following the documentation, I used "await User.find().populate('pics');" to migrate data in index method, but did not work.
Besides, should I include 'pics' key at store method, or userSchema 'pics' should be enough?
const userSchema = new mongoose.Schema({
name: {
type: String,
required: true,
trim: true
},
pics: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Pic"
}
],
});
const picSchema = new mongoose.Schema({
thumbnail: String,
description: String,
dev: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
},
);
const User = mongoose.model('User', userSchema);
const Pic = mongoose.model('Pic', picSchema)
async index(req, res, next) {
const users = await User.find().populate('pics');
res.status(200).json(
devs
);
},
async store(req, res) {
try {
const { name } = req.body;
let user = await User.create({
name,
pics
})
// await user.populate('pics').execPopulate();
res.send({ user })
}
} catch (error) {
res.status(400).send(error);
}
},
I worked a time ago with MongoDB and NodeJS. I think that you have a problem with the definitions. Also, you can read the documentation https://mongoosejs.com/docs/populate.html
You need to define the _id for collections (Schema).
const userSchema = new mongoose.Schema({
_id: new mongoose.Types.ObjectId(),
name: {
type: String,
required: true,
trim: true
},
pics: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Pic"
}
],
});
const picSchema = new mongoose.Schema({
_id: new mongoose.Types.ObjectId(),
thumbnail: String,
description: String,
dev: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
},
);
So, when you create a new User, the _id is completed (you can generate it or it can be generated automatically) and ignore the field pics. When you create a Pic, you need to read the _id of the User and assigned as 'dev', something like:
let pic = new Pic({
thumbnail: '', description: '',
dev: yourUser._id
});
Using this way to create documents, you can use the populate function.

node mongoose update two collections

I have two schemas, a "projects" schema, and an "applications" schema.
What is the most efficient way of creating a new entry in a collection and updating an existing entry in another collection based on data inside the new entry? Can I avoid making multiple API requests and somehow run a "stored procedure" on the mongoDB end to handle updating the Projects collection when there is a change in the Applications collection?
In this scenario, ideally when an application for a project is created, a new entry is created in the Applications collection and the Project in the Projects collection is updated to reflect the information in the Application.
Can I do this without making multiple api requests?
Project Schema:
// models product.js
const mongoose = require('mongoose');
const { ObjectId } = mongoose.Schema;
const projectSchema = new mongoose.Schema({
name: {
type: String,
trim: true,
required: true,
maxlength: 32
},
applications: {
type: Number,
default: 0
},
created_by: {
type: ObjectId,
ref: 'User'
},
applicants: {
type: Array,
default: []
}
}, {timestamps: true}
);
module.exports = mongoose.model("Project", projectSchema);
Application Schema:
const mongoose = require('mongoose');
const applicationSchema = new mongoose.Schema({
applicantId: {
type: ObjectId,
ref: 'User'
},
ownerId: {
type: ObjectId,
ref: 'User'
},
projectId: {
type: ObjectId,
ref: 'Project'
}
}, {timestamps: true});
module.exports = mongoose.model("Application", applicationSchema);
Note that these are separate schemas because they each carry around 15 fields, i've trimmed them down to post this question.
I suggest to use hooks for mongoose model, there is a post save hook which you can use on Application model to update Project and increment application count.
EDIT - Added Pseudo Code
Project Model
// models -> project.js
const mongoose = require('mongoose');
const {
ObjectId
} = mongoose.Schema;
const projectSchema = new mongoose.Schema({
name: {
type: String,
trim: true,
required: true,
maxlength: 32
},
applications: {
type: Number,
default: 0
},
created_by: {
type: ObjectId,
ref: 'User'
},
applicants: {
type: Array,
default: []
}
}, {
timestamps: true
});
projectSchema.statics = {
/**
* Find project by _id
*
* #param {ObjectId} _id
* #api private
*/
get: function (_id) {
return this.findOne({
_id
})
.exec();
}
}
module.exports = mongoose.model("Project", projectSchema);
Application Model
const mongoose = require('mongoose');
const projectModel = require("./project")
const applicationSchema = new mongoose.Schema({
applicantId: {
type: ObjectId,
ref: 'User'
},
ownerId: {
type: ObjectId,
ref: 'User'
},
projectId: {
type: ObjectId,
ref: 'Project'
}
}, {
timestamps: true
});
// Async hook
applicationSchema.post('save', function (doc, next) {
const relatedProject = projectModel.get(doc.projectId);
relatedProject.applications++;
relatedProject.save();
next();
});
module.exports = mongoose.model("Application", applicationSchema);

How to push data into array using mongoose, with schema having single only single object

I am learning Mongoose, and got struct on pushing data into array blogs.
my schema is
module.exports = function(mongoose) {
var UserSchema = new Schema({
count:String,
_id : {id:false},
blogs: [{ type: Schema.Types.ObjectId, ref: 'Blog' }]
},
{
timestamps: { createdAt: 'created_at', updatedAt: 'updated_at' }
});
var BlogSchema = new Schema({
blogs:[{
post : String,
title: String,
author : String,
userId: {
type: String,
default: function() {
return crypto.randomBytes(12).toString('hex');
}
},
_id: {type: String, required: true}
}],
});
var models = {
User : mongoose.model('User', UserSchema),
Blog : mongoose.model('Blog', BlogSchema)
};
return models;
}
Problem is here userSchema will always have/be a single object, whcih will keep track of count of total blogs.
I know it can be done using findOneAndUpdate but I don't have id/object created for UserSchema.
Any help is appreciated. Thanks

Resources