When I update any value on frontend it get update in mongodb except boolen value . when I update boolen value on frontend it create new document for that change in collection. below is my code snippet.
let threats = req.body.threat
let threatss = []
if (threats) {
await Promise.all(threats.map(async (threat) => {
threatss.push(
{
updateOne: {
filter: { "id": threat.id },
update: {
...threat
},
upsert: true,
new: true
}
}
)
}))
}
ProjectThreatModel.bulkWrite(threatss);
Related
I am trying to update an array to show the router is up by using a true or false statement.
But I am getting a response back that "record is updated" but I am not able to see the change in MongoDB collection.
This is my function I am running
exports = async function({ body }) {
const data = JSON.parse(body.text());
const ACAS_Mission = data.ACAS_Mission;
const terminal = data.terminals[0].terminal;
const router = data.terminals[0].XLESS.router;
const comstat = context.services
.get("mongodb-atlas")
.db("Comstat")
.collection("comstat");
// Find the document
const filter = { ACAS_Mission, "terminals.terminal": terminal };
const document = await comstat.findOne(filter);
console.log("Document:", JSON.stringify(document));
// Update the document
const updateFilter = { ACAS_Mission, "terminals.terminal": terminal };
const update = { $set: { "terminals.$[t].XLESS.router": router } };
const options = { arrayFilters: [{ "t.terminal": terminal }] };
const result = await comstat.updateOne(updateFilter, update, options);
console.log("Update result:", JSON.stringify(result));
return { message: "Record updated." };
};
and this is the document I am trying to update
MongoDB Document
The JSON Body that I am passing when I do a PUT
{
"ACAS_Mission": "xx53583",
"terminals": [
{
"terminal": "SNN573330",
"XLESS": {
"router": true
}
}
]
}
As you wrote in your comment, MongoDB processes the request, but there are no changes. That means that nothing in your datebase matched your query (as one may conclude from matchedCount being 0).
Check your query: Your screenshot shows that terminals contains an array containing another array containing an object. You are searching for an array directly containing an object, so adding [braces] around the statement might work.
Was able to change the JSON body and a few function fixes and it works!
{
"ACAS_Mission": "xx53583",
"terminals": [
[
{
"terminal": "SNN573330",
"NodeID": 251,
"XLESS": {
"router": false
}
}
]
]
In my application, I am attempting to update a object nested in an array as a below. When testing in postman, there is a delay causing me to have to make two requests in order to see the updated value.
if (taskStatus) {
const taskStatusNew = await Board.findOneAndUpdate(
{
"columns.tasks._id": req.params.id,
},
{
$set: {
"columns.$[].tasks.$[t]": req.body,
},
},
{
arrayFilters: [
{
"t._id": req.params.id,
},
],
}
);
res.status(200).json(taskStatusNew);
}
By default, findOneAndUpdate() returns the document as it was before the update was applied. So you have to set the new option to true if you are using mongoose.
const taskStatusNew = await Board.findOneAndUpdate(
{
"columns.tasks._id": req.params.id,
},
{
$set: {
"columns.$[].tasks.$[t]": req.body,
},
},
{
arrayFilters: [
{
"t._id": req.params.id,
},
],
new: true
}
);
Documentation article for reference: https://mongoosejs.com/docs/tutorials/findoneandupdate.html
If your question is like to return the updated value then use this,- {returnDocument: 'after'}, you just need to add this in other parameter, then it will give you updated value.
How to include aggregation in if condition ,do I need to use project or condition method in if condition above as well catalogue populate. I need to get the data from the mongo dB in the same order as video Ids array but it's coming in a different order so I decided to use aggregation to get the video in a proper order as in the video Ids array. Please help me to resolve this issue.
let filter = {$match:{
customerId: customerId,
_id: {
$in: _.map(videoIds, id => mongoose.Types.ObjectId(id)) || []
},
_isDeleted: false,
isActive: true
},
$lookup:{
from:'catalogues',
localField:'_isDeleted',
foreignField:'_id',
as:false
}
}
if (!req.isLocationWhitelisted) {
if (req._countryCode) {
$or=
filter.$match['languages.country'] = {
$in: req._countryCode
}
filter.$lookup['languages.country'] = {
$in: req._countryCode
}
,
filter.$match['languages.country.141'] = { $exists: true }
filter.$lookup['languages.country.141'] = { $exists: true }
}
}
let videoList = await Video.aggregate(filter);
Trying to simply include a field that has select set to false within the schema. Overriding it with select method is not working for some reason. Exclusion of other fields work but inclusion doesn't. In the following example I'm trying to include the "active_account" field. What could be causing this behavior?
Schema
const Schema = new mongoose.Schema({
active_account: {
type: Boolean,
default: true,
select: false
}
})
Function
exports.deactivate_user = async ( req , res , next ) => {
const user = await User.findByIdAndUpdate( req.params.id , { active_account: false } ).select( '+active_account' );
res.status( 200 ).json({
status: 'Success',
data: user
});
};
According to docs;
A.findByIdAndUpdate(id, update, options) // returns Query
So,
const user = await User.findByIdAndUpdate(
req.params.id, //id
{ active_account: false }, //update
{ select: 'active_account', new: true } //options
);
set new = true to get the updated version of data.
I have a Mongoose document (Mongoose 5.4.13, mongoDB 4.0.12):
var SkillSchema = new mongoose.Schema({
skill: { type: String },
count: { type: Number, default: 0 },
associatedUsers: [{ type : mongoose.Schema.Types.ObjectId, ref: 'User' }]
});
That I update as follows:
var query = { skill: req.body.skill };
var update = { $addToSet: { associatedUsers: req.params.id } };
var options = { upsert: true, new: true, setDefaultsOnInsert: true };
await skillSchema.findOneAndUpdate(query, update, options);
During this update, I would like to also update count to be equal to the length of associatedUsers.
Ideally I want this to happen at the same time as updating the other fields (i.e not in a subsequent update), either via a pre-hook or within findOneAndUpdate.
I've tried using a pre hook after schema definition:
SkillSchema.pre('findOneAndUpdate', async function(){
console.log("counting associated users");
this.count = this.associatedUsers.length;
next();
});
As well as using aggregate in my UPDATE route:
await skillSchema.aggregate([{ $project: { count: { $size: "$associatedUsers" } } } ])
But I can't get either to work.
Does anyone have any suggestions for how I could achieve this?
You could use $set like this in 4.2 which supports aggregation pipeline in update.
The first $set stage calculates a associatedUsers based on the previous and new value. $setUnion to keep the distinct associatedUsers values.
The second $set stage calculates tally based on the associatedUsers calculated in the previous stage.$size to calculate the length of associatedUsers values.
var query = {skill: req.body.skill};
var update = [{ $set: { "associatedUsers":{"$setUnion":[{"$ifNull":["$associatedUsers",[]]}, [req.params.id]] }}}, {$set:{tally:{ $size: "$associatedUsers" }}}];
var options = { upsert: true, new: true, setDefaultsOnInsert: true };
await skillSchema.findOneAndUpdate(query, update, options)
If any argument resolves to a value of null or refers to a field that is missing, $setUnion returns null. So just needed to safeguard our operation with $ifNull
About tally and associatedUsers.length
// define your schema object
var schemaObj = {
skill: { type: String },
associatedUsers: { type: Array }
};
// get the length of users
var lengthOfAsUsers = schemaObj.associatedUsers.length;
// add tally to schema object and set default to the length of users
schemaObj.tally = { type: Number, default: lengthOfAsUsers };
// and pass your schema object to mongoose.Schema
var SkillSchema = new mongoose.Schema(schemaObj);
module.exports = SkillSchema;
EDIT
you can update tally subsequently, but recommended solution would be to use this method
https://mongoosejs.com/docs/populate.html
const id = "nameSomeId";
SkillSchema.find({ _id: id }).then(resp => {
const tallyToUpdate = resp.associatedUsers.length;
SkillSchema.findOneAndUpdate({ _id: id }, { tally: tallyToUpdate }).then(
resp => {
console.log(resp);
}
);
});
The solution I have will only work on mongodb v 4.2 as it has option to use aggregate in the update and will only need one query as:
skillSchemafindOneAndUpdate(
{skill:"art"},
[
{ $set: {
associatedUsers:{
$cond:{
if: {$gte: [{$indexOfArray: ["$associatedUsers", mongoose.Types.ObjectId(req.params.id)]}, 0]},
then: "$associatedUsers",
else: { $cond:{
if: { $isArray: "$associatedUsers" },
then: {$concatArrays:["$associatedUsers",[mongoose.Types.ObjectId(req.params.id)]]},
else: [mongoose.Types.ObjectId(req.params.id)]
}}
}
}}},
{$set:{
associatedUsers:"$associatedUsers",
tally:{$size:"$associatedUsers"},
}}
],
{upsert:true,new:true}
)
ref: https://docs.mongodb.com/manual/reference/method/db.collection.update/#update-with-aggregation-pipeline
The "Group" field does not appear in the schema. On MongoDB Shell, these codes will work.
However, Mongoose will also give an error because the schema is validated.
Is the "Group" field a dynamic field? I think the problem with the schema will be solved.
var mongoose = require("mongoose");
var SkillSchema = new mongoose.Schema({
skill: { type: String },
tally: { type: Number, default: 0 },
associatedUsers: { type: Array },
group: { type: Array }
});