Mongoose update object inside a nested array - node.js

I know there are hundreds of same questions, but I've read them and can't get this to work.
What I want to do is to update the given object inside tasks array with given req.body params
I tried most of the solutions but probably wrongly implemented them. This is closest to what I can imagine working.
Example document
{
"_id" : ObjectId("5f421bf98bc1d33d7c646535"),
"todoSections" : [
{
"_id" : ObjectId("5f42202b9c6c3040ea0d5326"),
"name" : "first section",
"tasks" : [
{
"status" : 4,
"priority" : 2,
"_id" : ObjectId("5f42274952e6864b19252e37"),
"name" : "task 1",
"assignedUsers" : [],
"comments" : [],
"subTasks" : []
},
{
"status" : 4,
"priority" : 2,
"_id" : ObjectId("5f422a6377eaa74f2e403940"),
"name" : "task 2",
"creationDate" : ISODate("2020-08-23T08:35:47.497Z"),
"assignedUsers" : [],
"comments" : [],
"subTasks" : []
}
]
},
{
"_id" : ObjectId("5f42202f9c6c3040ea0d5327"),
"name" : "another section..",
"tasks" : []
},
],
"__v" : 0
}
My code
const mongodb = require("mongodb");
const { ObjectId } = require("mongodb");
Todo.updateOne(
{
_id: req.body.todoId,
},
{
$set: {
"todoSections.$[outer].tasks$[inner]": {
name: req.body.name,
status: req.body.status
},
},
},
{
arrayFilters: [
{ "outer._id": ObjectId(req.body.sectionId) },
{ "inner._id": ObjectId(req.body.taskId) },
],
},
(err, result) => {
if (!err) {
if (result.nModified === 0) {
res.status(400).send(result);
console.log(result);
return;
} else {
res.status(200).send("ok");
}
} else {
res.status(400).send(err);
console.log(err);
return;
}
}
);
Result returns:
{
"ok": 0,
"n": 0,
"nModified": 0
}

Related

text search returning empty array

my query is returning me an empty array when I try to text search in mongodb I already created an index into my database.
For example:
I have 2 data type of String declared in my model status and mac_address both of them already included in the text index. When I search for a mac_address it gives me the correct data but when I tried to search for the status it returns an empty array.
--Model--
const PhoneSchema = new mongoose.Schema({
status: {
type: String,
default: "DOWN"
},
mac_address: {
type: String,
unique: true
},
});
--Index--
db.phones.createIndex({
status: "text",
mac_address: "text"
});
--Route--
router.get('/search/:searchForData',
async function (req, res) {
try {
const searchPhone = await Phone.find({
$text: {
$search: req.params.searchForData
}
}, {
score: {
$meta: "textScore"
}
}).sort({
score: {
$meta: "textScore"
}
})
res.status(200).json(searchPhone);
} catch (err) {
return res.status(404).json({
error: err.message
});
}
});
db.phones.getIndexes()
[
{
"v" : 2,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "pingphony.phones"
},
{
"v" : 2,
"unique" : true,
"key" : {
"ip" : 1
},
"name" : "ip_1",
"ns" : "pingphony.phones",
"background" : true
},
{
"v" : 2,
"unique" : true,
"key" : {
"mac" : 1
},
"name" : "mac_1",
"ns" : "pingphony.phones",
"background" : true
},
{
"v" : 2,
"key" : {
"_fts" : "text",
"_ftsx" : 1
},
"name" : "$**_text",
"ns" : "pingphony.phones",
"weights" : {
"$**" : 1
},
"default_language" : "english",
"language_override" : "language",
"textIndexVersion" : 3
}
]
I expect the output of /phone/search/DOWN to be the data consisting of DOWN status but the actual output I get is []
Try making your query directly from mongo console:
db.phones.find({ $text: { $search: "DOWN" }})
Try using aggregation pipeline:
const searchPhone = await Phone.aggregate(
[
{ $match: { $text: { $search: "DOWN" } } },
{ $sort: { score: { $meta: "textScore" } } },
]
);
If you tried everything and it just didn't go well try using regexp:
const searchQuery = req.params.searchForData.replace(/[.*+?^${}()|[]\]/g, '\$&'); // escape regexp symbols
const searchPhone = await Phone.find({ status: new RegExp(${searchQuery}, 'i') });

update particular single subdocument in nested array in nodejs mongodb

I am new to nodejs and mongo db. I have nested subdocument type schema in mongo. Document type is Process => Subprocess => tasks => configs. These are in the format of nested arrays and can be multiple.
{
"_id" : ObjectId("5bcec0ee711fe511f4848c1d"),
"process_title" : "customer acquisition",
"subprocess" : [
{
"_id" : ObjectId("5bcec0f8711fe511f4848c1e"),
"subprocess_title" : "application",
"tasks" : [
{
"_id" : ObjectId("5bcec158711fe511f4848c1f"),
"task_title" : "pre screening",
"task_slug" : "pre-screening",
"task_configs" : [
{
"_id" : ObjectId("5bcec4b912582b01b84fe47a"),
"next_task" : "thanks"
}
]
},
{
"_id" : ObjectId("5bcec190711fe511f4848c20"),
"task_title" : "thanks",
"task_slug" : "thanks",
"task_configs" : [
{
"_id" : ObjectId("5bcec469ab23ab1fc0bbb9ed"),
"form_field" : "responseMessage",
"expression" : "=",
"expression_value" : "Approved4",
"success_task" : "signup",
"success_sub_process_id" : "5bcec0f8711fe511f4848c1e",
"fail_task" : "thanks",
"fail_sub_process_id" : "5bcec0f8711fe511f4848c1e"
}
]
},
{
"_id" : ObjectId("5bcec1c3711fe511f4848c21"),
"task_title" : "signup",
"task_slug" : "signup",
"task_configs" : [
{
"_id" : ObjectId("5bcec469ab23ab1fc0bbb9ed"),
"form_field" : "responseMessage",
"expression" : "=",
"expression_value" : "Approved4",
"success_task" : "signup",
"success_sub_process_id" : "5bcec0f8711fe511f4848c1e",
"fail_task" : "thanks",
"fail_sub_process_id" : "5bcec0f8711fe511f4848c1e"
}
]
}
]
}
],
"created_at" : ISODate("2018-10-23T06:34:22.676Z"),
"updated" : ISODate("2018-10-23T06:34:22.676Z"),
"__v" : 0
}
Now I want to update task_configs for a particular task. I am updating task_config on the basis of task_slug.
I found a way myself to update above query.
Workflow.updateOne({ "_id": new ObjectId(req.body.process_id), "subprocess._id": new ObjectId(req.body.sub_process_id), "subprocess.tasks.task_slug": req.body.task_slug },
{
$set: {
'subprocess.$.tasks.$[j].task_configs': req.body.task_configs
}
},
{
arrayFilters: [
{
"j.task_configs": req.body.task_configs
}]
})
.then(function (resp) {
console.log(resp)
res.json({ status: 'success', resp });
}).catch(function (err) {
res.status(500).json(err);
})

how to return response using mongo's aggregate?

I'm starting with mongodb, I'm using aggregate function which gives me the last user of the last element into the sampleStatus array. (I mean the latest record added to sampleStatus)
I have a collection of samples like this :
{
"_id" : ObjectId("58d6cbc14124691cd8154d72"),
"correlativeCode" : "CSLLPA53E20M017W",
"registrationMethod" : "taken",
"originPlace" : "SOMEPLACE",
"temperature" : 16,
"sampleStatus" : [
{
"nameStatus" : "status1",
"place" : "place1",
"rejectionReason" : "Nothing",
"user" : "user1",
"_id" : ObjectId("58d6cbc14124691cd8154d73")
},
{
"nameStatus" : "status2",
"place" : "place2",
"rejectionReason" : "Nothing",
"user" : "user4",
"_id" : ObjectId("58d6cbc14124691cd8154d73")
},
{
"nameStatus" : "status3",
"place" : "place3",
"rejectionReason" : "Nothing",
"user" : "user3",
"_id" : ObjectId("58d6cbc14124691cd8154d73")
},
{
"nameStatus" : "status4",
"place" : "place4",
"rejectionReason" : "Nothing",
"user" : "user1",
"_id" : ObjectId("58d6cbc14124691cd8154d73")
},
{
"nameStatus" : "status5",
"place" : "place5",
"rejectionReason" : "Nothing",
"user" : "user5",
"_id" : ObjectId("58d6cbc14124691cd8154d73")
}
]
}
This is the function I'm using:
db.collection.aggregate([
{ "$match": { "correlativeCode": "CSLLPA53E20M017W" } },
{ "$redact": {
"$cond": [
{ "$eq": [
{ "$let": {
"vars": {
"item": { "$arrayElemAt": [ "$sampleStatus", -1 ] }
},
"in": "$$item.user"
} },
"user5"
] },
"$$KEEP",
"$$PRUNE"
]
}}
])
When I use this in mongodb's console, it works.. but, when I try to adapt this in a controller.js
VerifySample: function (req, res) {
var id = req.body.idSample;
var idUser=req.body.currentuser;
SamplePatientModel.aggregate([
{ $match: { _id: id } },
{ $redact: {
$cond: [
{ $eq: [
{ $let: {
vars: {
"item": { $arrayElemAt: [ "$sampleStatus", -1 ] }
},
in: "$$item.user"
} },
idUser
] },
"$$KEEP",
"$$PRUNE"
]
}}
],
function(err, _SamplePatient) {
console.log('entry function');
if (err) {
console.log('Entry err');
return res.status(500).json({message: 'Error SamplePatient', error: err});
}
//No results
if(!_SamplePatient){
console.log('no results ');
return res.status(404).json({message: 'error', error: err});
}
console.log('Got it');
console.log(_SamplePatient);
return res.status(200).json(_SamplePatient);
}
);}
It gives me following response:
[]
console.log(_SamplePatient) doesn't show anything
the words "entry function" are printed in console
what am I doing wrong?
Please, help me.
Thanks.
Casting ObjectId in mongoose is not supported in aggregation pipeline.
So you've to explicitly cast the string value to ObjectId in the aggregation pipeline.
Update your match stage to below.
{ $match: { _id: mongoose.Types.ObjectId(req.body.idSample) } }
Here is the issue
https://github.com/Automattic/mongoose/issues/1399
Mongoose Docs:
http://mongoosejs.com/docs/api.html#model_Model.aggregate

Can't create correct query to reach mongodb document

I need to translate a mongo shell command to the correct mongoose update in my express route.
The :id in the url is the ObjectId # in my document. The req.body will have an object with the key/values for title, season_number, episode_number, and watched. I thought I'd just replace this part of the mongo shell query
{ 'season_number': 1, 'episode_number': { $gt: 4, $lt: 6 },
with
{
'season_number': req.body.season_number,
'episode_number': {
$gt: req.body.episode_number - 1,
$lt: req.body.episode_number + 1
}
}
in the query but that did not find the document.
Route
router.put('/api/shows/:id/episodes/add', function(req, res){
var query = {
/*
I've tried many things but my query never returns the document
to update so I am pretty sure the problem is here
*/
}
var setObject = {
$push:{
'episodes':req.body
}
}
TV.update(query, setObject, function(err, results){
if(err){console.log(err)}
else{res.json(results)};
})
})
Mongo Shell Document
{
"_id" : ObjectId("581972b7b04acfc99b4dae0f"),
"title" : "Designated Survivor",
"poster" : "https://images-na.ssl-images-amazon.com/images/M/MV5BMTY5NzYzODU4N15BMl5BanBnXkFtZTgwNzA1MjUwMDI#._V1_.jpg",
"rated" : "TV-14",
"program_time" : 60,
"network" : "ABC",
"airs_on" : [
"Wednesday"
],
"streams_on" : [
"123Movies",
"Hulu Plus"
],
"genre" : [
"Drama"
],
"episodes" : [
{
"season_number" : 1,
"episode_number" : 1,
"title" : "Pilot",
"watched" : true
},
{
"season_number" : 1,
"episode_number" : 2,
"title" : "The First Day",
"watched" : true
},
{
"season_number" : 1,
"episode_number" : 3,
"title" : "The Confession",
"watched" : true
},
{
"season_number" : 1,
"episode_number" : 4,
"title" : "The Enemy",
"watched" : true
},
{
"season_number" : 1,
"episode_number" : 5,
"title" : "The Mission",
"watched" : true
},
{
"title" : "The Interrogation",
"season_number" : 1,
"episode_number" : 6,
"watched" : false
}
],
"test" : "gt four less than 6"
}
Mongo Shell Command that added the 6th Episode
db.tvShows.findOneAndUpdate(
{
$and: [
{ '_id': ObjectId('581972b7b04acfc99b4dae0f') },
{ 'episodes': {
$elemMatch: {
'season_number': 1,
'episode_number': { $gt: 4, $lt: 6 }
}
} }
]
},
{
$push: {
'episodes': {
'title': 'The Interrogation',
'season_number': 1,
'episode_number': 6,
watched: false
}
}
}
)

Node : Mongoose Updating User Schema with arrays

Here is my User Schema
{
"user_collection":[
{
"_id":"xxx",
"name":"NAME",
"prescription":
{
"doctor_id":
[{
"_id":"xxx",
"medicine_id":"MEDICINE_ID",
}]
},
"meal":{
"meal_name":{
"start_time":"START_TIME",
"end_time":"END_TIME"
}
},
"created_at":"CREATED_AT",
"updted_at":"UPDATED_AT"
}
]
}
Note : _id given just for understanding
I need to insert document inside the prescription array. Here is the condition
If the new doctor_id is given, it should add in the prescription array like
{
"_id" : ObjectId("5813288eaa0f1231de477d92"),
"name" : "andrew",
"prescription" : [
{
"prescription" : [
{
"_id" : ObjectId("58143d484e26a229873b0528"),
"medicine_id" : "10011241343"
}
],
"_id" : ObjectId("58143d484e26a229873b0527"),
"doctor_id" : "5813221ace684e2b3f5f0a6d"
}
]
}
And if i given the doctor_id that already exists it should add like
{
"_id" : ObjectId("5813288eaa0f1231de477d92"),
"name" : "andrew",
"prescription" : [
{
"prescription" : [
{
"_id" : ObjectId("58143d484e26a229873b0528"),
"medicine_id" : "10011241343"
}
],
"prescription" : [
{
"_id" : ObjectId("58143d484e26a229873b0529"),
"medicine_id" : "10011241349"
}
],
"_id" : ObjectId("58143d484e26a229873b0527"),
"doctor_id" : "5813221ace684e2b3f5f0a6d"
}
]
}
What i have tried is
dbModel.user.update({
_id: req.body.user_id
}, {
$set: {
prescription: [ { "doctor_id" : req.body.doctor_id, "prescription" : [
{
"medicine_id" : req.body.medicine_id
}]} ],
}
}, {
upsert: true
}, function(err) {
if (err) {
res.status(202).json({
"success": "0",
"message": err
})
} else {
res.status(200).json({
"success": "1",
"message": "Prescription given successfully"
});
}
})
I don't know how to check whether the doctor_id already exists and if it does not exists it should add a new array, and if it exists it should add inside the existing arrays
Take a look in this answer.
But basically you can use the $ operator which identifies an element in an array.
You can see here some mongodb array operators.

Resources