MongoDB - update specific array element by id [duplicate] - javascript

This question already has answers here:
How to Update Multiple Array Elements in mongodb
(16 answers)
Closed 3 days ago.
Ive been trying these since yesterday but I couldnt make it.
I have 2 different Schemas, the User Schema and the Vital Signs Schema. The Vital Signs Schema is inside the userSchema as an array. What i need to do is to edit an specific vitalSigns object with an unique Id
Here is a postman example of the info i need to update
const userSchema = new mongoose.Schema({
email:{type: String, required: true},
password:[{type: String, required: true}],
confirmPassword:[{type: String, required: true}],
personalData: personalDataSchema,
vitalSigns: [vitalSignsSchema],
})
const vitalSignsSchema = new mongoose.Schema({
systolic: { type: 'Number', required: false },
diastolic: { type: 'Number', required: false },
temperature: { type: 'Number', required: false },
pulse: { type: 'Number', required: false },
rate: { type: 'Number', required: false },
blood: { type: 'Number', required: false },
date: { type: 'Date', required: false },
})
My route is catching both userId and vitalSigns because i tried to make it work with a lot of ways but i couldn't
Router.post('/user/:userId/vitalSignsEdit/:vitalId', async (req, res) => {
userServices.editVitalSigns(req.params.userId,req.params.vitalId, req.body)
})
Here is one example of a way that I tried to use to make it work but instead of updating the specific vitalSigns Id, it created another object of vitalSigns with the same Id that i tried to change.
User.findById(userId)
.then( user => {
if(user) {
if(user.vitalSigns.find( e => e._id === data._id)) {
User.updateOne({_id: userId}, { vitalSigns: [...user.vitalSigns, data] })
.then(e => console.log(e), i => console.log(i))
}
}
})
Hope someone could help me with these.

You could use $push
User.updateOne({_id: userId}, { $push: { vitalSigns: data } })

Use $ to access the array element matched.
db.collection.update({
"vitalSigns._id": "vs1"
},
{
$set: {
"vitalSigns.$.modified": true
}
})
Mongo Playground

Related

Mongoose findByIdAndUpdate method not incrementing document value

I am trying to update the like count of job posts in my application using the $inc operator and the findByIdAndUpdate method from Mongoose. The correct document is being retrieved and returned but the like count for the job post never moves up from 0 and no updates are performed in the database collection.
Below is the code I am currently using to perform the update.
Jobs.findByIdAndUpdate(req.params._id , { $inc: {likes: 1}} , {new: true})
.then((ret) => {
res.send(ret)
})
Job schema
const mongoose = require('mongoose');
let JobSchema = mongoose.Schema({
student_name: {
type: String,
required: true
},
subject: {
type: String,
required: true
},
grade: {
type: Number,
required: true
},
area: {
type: String,
required: true
},
desc: {
type: String,
required: true
},
accepted: {
type: Boolean,
required: true,
default: false
},
tutor_name: {
type: String,
required: false
},
} , {collection: 'jobs'});
let Job = mongoose.model('Job' , JobSchema);
module.exports = Job;
Any insight into what is preventing the update from performing would be greatly appreciated
I have tried using two queries, one to retrieve the current likes of a post and another to manually update the doc with the incremented value. I have tried nesting the queries using .then() statements and have also tried the updateOne() and findOneAndUpdate() methods as alternatives. I have tried experimenting with the $set and $inc operators in my queries to see if either of them perform the changes, but neither do.
I am expecting the incremented 'likes' value to be reflected in the database and for the updated job document to be returned and echoed back to the console.
Your schema is missing a likes field, which means Mongoose will remove it from queries/updates (since it doesn't match the schema). Make sure to add it:
likes: {
type: Number,
default: 0
}
Can you try something like this (adding [] around update):
Jobs.findByIdAndUpdate(req.params._id , [{ $inc: {likes: 1}}] , {new: true})
.then((ret) => {
res.send(ret)
})
EDITED:
Jobs.findByIdAndUpdate(req.params._id , [{ $set: {likes: "$likes"+1}}] , {new: true})
.then((ret) => {
res.send(ret)
})

MongoDB not showing full document when queried [duplicate]

This question already has answers here:
Join two collections using mongoose and get data from both
(1 answer)
Mongoose populate does not populate array
(3 answers)
How to populate array of objects in mongoose
(2 answers)
Closed 11 months ago.
I am trying to pull data (particularly, the memberships array) from a certain user.
_id:623db49b9da63a7758307d68
email:"test#test.com"
username:"test"
salt:"eb83e08efef62630c46b1809c7671db2109ceccff9d66862c93df1e3825c1354"
hash:"e419edb1bc481d5c87dd223a7f1dc20bece679fad1a3c1afe05dfabba341c0a9913a60..."
__v:0
memberships:Array
0:623dc03f72436863b72c396e
1:623dc869b61c3799494b2657
However, when I request the document, it does not retrieve the memberships portion.
{
_id: new ObjectId("623db49b9da63a7758307d68"),
email: 'test#test.com',
username: 'test',
__v: 0
}
The code below is responsible for pulling the information from the DB and then also logs what was pulled.
module.exports.showContent = async(req, res, next) => {
try {
const user = await User.findById(req.user.id);
console.log(user)
res.render('index', { user })
} catch (e) {
console.log(e)
res.render('index')
}
}
Funny enough, if there is only one ref in the array, it will show up in the console.log!
{
_id: new ObjectId("623db49b9da63a7758307d68"),
email: 'test#test.com',
username: 'test',
__v: 0,
memberships: new ObjectId("623dc869b61c3799494b2657")
}
Schema model in question:
const UserSchema = new Schema({
email: {
type: String,
required: true,
unique: true,
},
username: {
type: String,
required: true,
unique: true,
},
roles: String,
memberships: {
type: Schema.Types.ObjectId,
ref: 'Community',
},
posts: {
type: Schema.Types.ObjectId,
ref: 'Posts',
},
comments: {
type: Schema.Types.ObjectId,
ref: 'Comments',
}
})
UserSchema.plugin(passportLocalMongoose);
module.exports = mongoose.model('User', UserSchema);
My other collections do not seem to have the same issue when it comes to refs inside an array.
I have tried using .populate() to populate the data. Tried using path: and populate: within the method. Tried googling the issue, but to no luck.

MongoDB / NodeJS can't push to array

I am trying to add tags to existing tags in a MongoDB collection with this Schema:
const workSchema = new mongoose.Schema({
title: {
type: String,
required: "Tile can't be blank"
},
description: {
type: String
},
imageURL: {
type: String,
unique: true
},
workURL:{
type: String,
unique: true
},
tags:{
type:Array
},
createdDate: {
type: Date,
default: Date.now
}
});
const Work = mongoose.model('Work', workSchema);
module.exports = Work;
I made an API that makes a PUT request to "/api/work/:workId/tags"
exports.updateTags = (req, res) =>{
try{
const newTags = req.body.tags.split(',');
newTags.forEach(tag => {
db.Work.update(
{"_id": req.params.workId},
{
$push:{
tags: tag
}
}
)
})
res.status(200).send({message : "tags updated"})
}
catch(error){
res.status(400).send(error)
}
}
request.body:
{
tags:"a,b,c"
}
The problem is that the array won't update with the new tag values
I searched for other ways to update in the docs and on the web but I didn't find any solutions.
You haven't defined _id in your workSchema so the type of _id would be ObjectId
But req.params.workId is probably a String, so querying an ObjectId with a String won't work.
So you should convert req.params.workId to ObjectId using mongoose.Types.ObjectId
{ "_id": mongoose.Types.ObjectId(req.params.workId) }
But you can improve your code a bit more by using .findByIdAndUpdate and $each operator
.findByIdAndUpdate will automatically convert your _id to ObjectId
You can use $each to $push multiple array elements at the same time without using .forEach
Work.findByIdAndUpdate(req.params.workId, {
$push: { "tags": { $each: newTags } }
})

Asynchronous Programming in node js to pass constants/predefined mandatory values through mongoose model

I have multiple questions, please go through my code.
1) how to pass constants/predefined mandatory values through model?
For eg. I have some fields which user must be passing the values and some constants to pass on inside the kafkaSchema.config[ ] and also livySchema.args[ ]. The code i want to pass through is in second question on the same question thread.
const mongoose = require('mongoose');
const livy_schema = mongoose.Schema({
file: { type: String, required: true },
name: { type: String, required: true },
className: { type: String, required: true },
args: [{ type: mongoose.Schema.Types.Mixed, required: true }] //here i have constants to pass on to
});
const kafka_schema = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
name: { type: String, required: true, unique: false },
config: { type: mongoose.Schema.Types.Mixed, required: true } //here i have constants to pass on to
});
const enrichedEventSchema = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
projectId: { type: mongoose.Schema.Types.ObjectId, ref: 'Project', required: true },
name: { type: String, required: true, unique: true },
description: { type: String, required: false },
type: { type: String, enum: ["Enriched"], required: true },
format: { type: String, enum: ["JSON", "DELIMITED", "FixedWidth", "LOG"], required: true },
kafka: [kafka_schema],
livy: [livy_schema] // how to make this schema required:true?
});
module.exports = mongoose.model('EnrichedEvent', enrichedEventSchema);
2) how to make this code to run asynchronously, Right now its working synchronously. For example, Its able to save the eventdata in event collection in database, then its updating the project collection, then calling axios.post method to call my livy server and kafka server in order. What i want to do is save the eventdata in event collection in database, then update the project collection (synchronously), meanwhile I want to call my livy and kafka server at the same time (Asynchronously).
router.post("/:projectId/events/enriched", (req, res, next) => {
const enrichedEvent = new EnrichedEvent({
_id: mongoose.Types.ObjectId(),
name: req.body.name,
projectId: req.params.projectId, //taking from url
description: req.body.description,
type: req.body.type,
format: req.body.format,
kafka: req.body.kafka,
livy: req.body.livy
});
enrichedEvent.save()
.then(result => {
console.log(result);
res.status(201).json({
message: "Event stored",
createdEvent: {
_id: result._id,
projectId: result.projectId,
name: result.name,
description: result.description,
type: result.type,
kafka: result.kafka,
livy: result.livy
}
});
Project.findOneAndUpdate({ _id: result.projectId },
{ $push: { enrichedEvents: result._id } })
axios.post("http://52.xxx.xxx.199:8998/batches", result.livy)
.then(function (response) {
console.log(response);
})
.then(axios.get("http://52.xxx.xxx.199:8998/batches/"), function (res) {
console.log(res);
})
axios.post("http://52.xxx.xxx.199:8083/connectors", result.kafka)
.then(function (response) {
console.log(response);
})
.catch(err => {
console.log(err);
res.status(500).json({
error: err
});
});
});
});
Question may seem bit lengthy, but valid question to ask on SO. Please guide me to right direction.
1)
const enrichedEventSchema = mongoose.Schema({
// ...
livy: { type: [livy_schema], required: true }
});
2)
return enrichedEvent.save().
then(result => {
// ...
return Project.findOneAndUpdate(/*...*/);
}).
then(() => {
// ...
return Promise.all([axios.post(/*...*/), axios.post(/*...*/]);
});
Hey try the following:
1) for saving user's entered configurations and also having default constants. You could use mongoose pre save hook.
https://mongoosejs.com/docs/middleware.html#pre
livy_schema.pre('save', function(next) {
this.args = { ...this.args, ...CONSTANTS }; //I'm use es6's spread operator
next();
});
kafka_schema.pre('save', function(next) {
this.config = { ...this.config, ...CONSTANTS }; //I'm use es6's spread operator
next();
});
2) For second question: try following:
axios.all([
axios.post("http://52.221.178.199:8998/batches", result.livy),
axios.post("http://52.221.178.199:8083/connectors", result.kafka)
]);

MongoDB w/ Mongoose - Where to put syntax to ensureIndex spanning multiple fields?

I'm trying to implement this solution and I'm not sure where to put it. I see the db variable called frequently, but I'm still new to node and mongoDb, so I don't know how to call it in my Model. Here is the syntax to ensure an index spanning multiple fields...
db.collection.ensureIndex( {
description: "text",
title: "text"
} );
Here is my model...
// Module dependencies.
var mongoose = require('mongoose'),
config = require('../../config/config'),
Schema = mongoose.Schema,
findOrCreate = require('mongoose-findorcreate'),
textSearch = require('mongoose-text-search');
// Product Schema
var ProductSchema = new Schema({
created: {
type: Date,
default: Date.now
},
retailer: {
type: String,
required: true,
trim: true
},
retailer_category: {
type: String,
required: true,
trim: true
},
product_id: {
type: String,
required: true,
trim: true
},
link: {
type: String,
trim: true
},
title: {
type: String,
trim: true
},
price: {
type: Number
},
// Rating - 0 out of 5 (can be decimal)
rating: {
type: Number
},
description: {
type: String,
trim: true
},
variations: {
type: Schema.Types.Mixed,
default: []
},
images: {
type: Boolean,
default: false
}
});
// Validations
ProductSchema.index({ retailer: 1, product_id: 1 }, { unique: true });
// Statics
ProductSchema.statics = {
load: function(id, cb) {
this.findOne({
_id: id
}).exec(cb);
}
};
// Plug-Ins
ProductSchema.plugin(findOrCreate);
ProductSchema.plugin(textSearch);
mongoose.model('Product', ProductSchema);
var Product = mongoose.model('Product', ProductSchema);
Product.ensureIndexes( function(err) {
if (err) {
console.log(err);
}
})
It's worth noting:
When your application starts up, Mongoose automatically calls ensureIndex for each defined index in your schema. While nice for development, it is recommended this behavior be disabled in production since index creation can cause a significant performance impact. Disable the behavior by setting the autoIndex option of your schema to false.
from http://mongoosejs.com/docs/guide.html
I scratched my head over this one too. After digging around the mongoose test cases, I found that ensureIndex resides in a mongoose model's collection property.
var ProductModel = mongoose.model('Product', ProductSchema);
ProductModel.collection.ensureIndex({
description : 'text',
title : 'text'
}, function(error, res) {
if(error){
return console.error('failed ensureIndex with error', error);
}
console.log('ensureIndex succeeded with response', res);
});
Note that a callback is required, or Mongo will throw the error:
Error: Cannot use a writeConcern without a provided callback

Categories

Resources