Mongoose delete an item in an array - arrays

i am a beginner in mongoose and i am trying to delete an element in array but i am facing troubles to do it
my schema is like this
name : {
type: String,
trim : true
},
pictures: {
type : Array,
required : false
},
and in my database it looks like this
{
"_id" : ObjectId("5eb67e7c74b35b205362b7f4"),
"title" : "john doe",
"pictures" : [
"img1.jpg",
"img2.png",
"img3.jpg",
"img4.jpg",
"img5.jpg"
]
}
how can i delete an item in the array of pictures?

You need $pull operator:
await Model.updateOne({"_id" : ObjectId("5eb67e7c74b35b205362b7f4")}, {$pull: { "pictures": "img1.jpg"}});

Related

MongoDB query to retrieve a specific value from the document located in a array

I am trying to make a request in a document with mongodb.
In this document
{
"_id" : ObjectId("5bd19a92da24674fdabd26b6"),
"search" : "try",
"name" : "try",
"email" : "yes#gmail.com",
"password" : "$2a$10$YIRuApqDy/L8HU7R1k2SB.aC2hqH8xFDbl3/muF7PsoN6/SGzsH4q",
"color" : 0,
"profil" : "",
"banner" : "",
"desc" : "",
"date" : 45587899,
"friend" : [
{
"id" : ObjectId("5bcee588ae409f434d35c76c")
}
],
"groupes" : [ ]
}
I'm looking to get just the id in friend, not all of the document just 1 id in friend with where i try this :
db.users.find({$and:[{"friend.id":"ObjectId(5bcee588ae409f434d35c76c)"},{"search":"try"}]})
It's not working i got no result.
Thank you for helping me.
I am not 100% sure I do understand your question properly. You should be able to query the described document via the following query:
find(
/* query by 'search' and the specific friend-id */
{'friend.id': ObjectId("5bcee588ae409f434d35c76c"), search: 'try'},
/* return only that 'friend' element which matches the queried 'friend-id' */
{_id:0, friend:{$elemMatch:{id:ObjectId("5bcee588ae409f434d35c76c")}}}
)
You get the following result:
{
"friend" : [
{
"id" : ObjectId("5bcee588ae409f434d35c76c")
}
]
}
db.users.find({
friend: {
$elemMatch: {
id: ObjectId("5bcee588ae409f434d35c76c")
}
},
search: 'try'
})

Remove element from array in mongoose

i am working on nodejs/express
I want to delete element in array in mongoose
i have document in this format
{
"_id" : ObjectId("5a2e19223e50551504b316c0"),
"username" : "nikhil",
"email" : "nikhil#itradicals.com",
"password" : "$2a$10$f3NvrTywIezlzKcZLWSU0O98gn6Mc.Q8B0ZNEDG2F66f4rwyo65Yu",
"companyname" : "itr",
"role" : "vendor",
"verify" : "true",
"createddate" : ISODate("2017-12-10T18:30:00.000+0000"),
"account" : [
{
"Region" : [
"North America",
"Africa",
"Asia"
]
},
{
"Category" : [
"Group 1",
"Group 2",
"Group 3"
]
}
]
}
i want to remove only Region field using mongoose query i m getting
data dyanamically so user can delete any array either it is Region or
Category. i m getting array name which i want to delete in parameter
"field".
module.exports.setupAccount = function(id,field,callback){
var query = { _id: id};
User.findOneAndUpdate(query,{ $set: { account.Region:[] }}, callback);
}
i am new to nodejs and mongoose
thanks in advance
If you don't want to keep the empty document after removing the field you can simply $pull the entire element from the array:
module.exports.setupAccount = function(id,field,callback){
var query = { _id: id };
User.findOneAndUpdate(query, { $pull: { "account": { field: { $exists: true } } } }, callback);
}
You can use below function.
Use computed property names to dynamically pass the field to unset and query expression.
Query to verify for array existence followed by $unset to remove array.
$ positional operator to dynamically locate array based on query criteria. You can hardcode the array index if you know the array position.
module.exports.setupAccount = function(id, field, callback){
var query = { "_id": id, ['account.' + field]:{"$exists":true}};
var unset = {"$unset":{['account.$.' + field]:""}};
User.findOneAndUpdate(query, unset, callback);
}

Updating Nested Array Mongoose

I am working on an express js application where I need to update a nested array.
1) Schema :
//Creating a mongoose schema
var userSchema = mongoose.Schema({
_id: {type: String, required:true},
name: String,
sensors: [{
sensor_name: {type: String, required:true},
measurements: [{time: String}]
}] });
2)
Here is the code snippet and explanation is below:
router.route('/sensors_update/:_id/:sensor_name/')
.post(function (req, res) {
User.findOneAndUpdate({_id:req.body._id}, {$push: {"sensors" :
{"sensor_name" : req.body.sensor_name , "measurements.0.time": req.body.time } } },
{new:true},function(err, newSensor) {
if (err)
res.send(err);
res.send(newSensor)
}); });
I am able to successfully update a value to the measurements array using the findOneAndUpdate with push technique but I'm failing when I try to add multiple measurements to the sensors array.
Here is current json I get if I get when I post a second measurement to the sensors array :
{
"_id": "Manasa",
"name": "Manasa Sub",
"__v": 0,
"sensors": [
{
"sensor_name": "ras",
"_id": "57da0a4bf3884d1fb2234c74",
"measurements": [
{
"time": "8:00"
}
]
},
{
"sensor_name": "ras",
"_id": "57da0a68f3884d1fb2234c75",
"measurements": [
{
"time": "9:00"
}
]
}]}
But the right format I want is posting multiple measurements with the sensors array like this :
Right JSON format would be :
{
"_id" : "Manasa",
"name" : "Manasa Sub",
"sensors" : [
{
"sensor_name" : "ras",
"_id" : ObjectId("57da0a4bf3884d1fb2234c74"),
"measurements" : [
{
"time" : "8:00"
}
],
"measurements" : [
{
"time" : "9:00"
}
]
}],
"__v" : 0 }
Please suggest some ideas regarding this. Thanks in advance.
You might want to rethink your data model. As it is currently, you cannot accomplish what you want. The sensors field refers to an array. In the ideal document format that you have provided, you have a single object inside that array. Then inside that object, you have two fields with the exact same key. In a JSON object, or mongo document in this context, you can't have duplicate keys within the same object.
It's not clear exactly what you're looking for here, but perhaps it would be best to go for something like this:
{
"_id" : "Manasa",
"name" : "Manasa Sub",
"sensors" : [
{
"sensor_name" : "ras",
"_id" : ObjectId("57da0a4bf3884d1fb2234c74"),
"measurements" : [
{
"time" : "8:00"
},
{
"time" : "9:00"
}
]
},
{
// next sensor in the sensors array with similar format
"_id": "",
"name": "",
"measurements": []
}],
}
If this is what you want, then you can try this:
User.findOneAndUpdate(
{ _id:req.body._id "sensors.sensor_name": req.body.sensor_name },
{ $push: { "sensors.0.measurements": { "time": req.body.time } } }
);
And as a side note, if you're only ever going to store a single string in each object in the measurements array, you might want to just store the actual values instead of the whole object { time: "value" }. You might find the data easier to handle this way.
Instead of hardcoding the index of the array it is possible to use identifier and positional operator $.
Example:
User.findOneAndUpdate(
{ _id: "Manasa" },
{ $push: { "sensors.$[outer].measurements": { "time": req.body.time } } }
{ "arrayFilters:" [{"outer._id": ObjectId("57da0a4bf3884d1fb2234c74")}]
);
You may notice than instead of getting a first element of the array I specified which element of the sensors array I would like to update by providing its ObjectId.
Note that arrayFilters are passed as the third argument to the update query as an option.
You could now make "outer._id" dynamic by passing the ObjectId of the sensor like so: {"outer._id": req.body.sensorId}
In general, with the use of identifier, you can get to even deeper nested array elements by following the same procedure and adding more filters.
If there was a third level nesting you could then do something like:
User.findOneAndUpdate(
{ _id: "Manasa" },
{ $push: { "sensors.$[outer].measurements.$[inner].example": { "time": req.body.time } } }
{ "arrayFilters:" [{"outer._id": ObjectId("57da0a4bf3884d1fb2234c74"), {"inner._id": ObjectId("57da0a4bf3884d1fb2234c74"}}]
);
You can find more details here in the answer written by Neil Lunn.
refer ::: positional-all
--- conditions :: { other_conditions, 'array1.array2.field_to_be_checked': 'value' }
--- updateData ::: { $push : { 'array1.$[].array2.$[].array3' : 'value_to_be_pushed' } }

Adding object to array in array in MongoDB

I have this data structure (classes with comments) and I want to add a 1-level deep reply. This means that I'd like to add another object on a "comentarios" element.
How can I achieve this with mongo?
This means: Match cursada (db) id, match clase (first array) id, match comment (second array) id, then add a new element there.
db.cursada.find({"_id": ObjectId("55444f56e5e154f7638b456a")}).pretty()
{
"_id" : ObjectId("55444f56e5e154f7638b456a"),
"clases" : [
{
"_id" : "554e7f2fe5e154797d8b4578",
"titulo" : "qewewqewq"
},
{
"_id" : "554e8be0e5e154dc698b4582",
"titulo" : "la mejor clase"
},
{
"_id" : "554eb90de5e154dd698b458b",
"comentarios" : [
{
"_id" : ObjectId("55a021afe5e154cf098b4567"),
"nombreUsuario" : "nombre",
"texto" : "432432423"
}
],
"titulo" : "Peeling - cosa"
},
{
"_id" : "554e91a0e5e154797d8b4587",
"titulo" : "fdsfdsa"
},
{
"_id" : "554f8f50e5e154dd698b458f",
"titulo" : "clase2"
},
{
"_id" : "554f99dae5e154797d8b45a7",
"titulo" : "con profesor"
},
{
"_id" : "554fa4a0e5e154797d8b45c4",
"titulo" : "profesor nombre nombre"
},
{
"_id" : "5557b37be5e154e07f8b4567",
"titulo" : "Dermatologia I"
},
{
"_id" : "5557c701e5e154066d8b456c",
"titulo" : "Acido hialuronico"
}
],
"curso" : "552fa5f1e5e1542e628b4567",
"fechaFin" : "2015-05-22T03:00:00.000Z",
"fechaIni" : "2015-05-08T03:00:00.000Z",
"titulo" : "cremotas"
}
Getting this result:
{
"_id" : ObjectId("55444f56e5e154f7638b456a"),
"clases" : [
{
"_id" : ObjectId("554eb90de5e154dd698b458b"),
"comentarios" : [
{
"_id" : ObjectId("55a021afe5e154cf098b4567"),
"nombreUsuario" : "nombre",
"texto" : "432432423",
----------------HERE
"replies": [
{ "_id": ....,
"user": ....,
"text":....,
"date":....
}]
----------------HERE
}
],
"titulo" : "Peeling - cosa"
},
]
}
One twisted example!
Luckily it presents no problem to MongoDB and its $elemMatch query operator:
Model.update({
_id: "55444f56e5e154f7638b456a",
classes: {
$elemMatch: {
_id: "554eb90de5e154dd698b458b",
}
}
}, {
$push: {
'classes.$.comentarios': {
nombreUsuario: 'New comment nombreUsuario',
texto: '111242515'
}
}
}, function(err, count) {
console.log('Updated ' + count + ' document');
});
What happens here?
First, we're specyfing specific course ("cursada") to update:
_id: "55444f56e5e154f7638b456a"
Then, using $elemMatch operator, we're restricting result of the query to contain only one class:
classes: {
$elemMatch: {
_id: "554eb90de5e154dd698b458b",
}
}
Now, having found specific class to update, we can finally add new comment to it. Here's our update query:
$push: {
'classes.$.comentarios': {
nombreUsuario: 'New comment nombreUsuario',
texto: '111242515'
}
}
$push operator tells MongoDB to add new comment to specified array of comments.
'classes.$.comentarios' specifies which nested comentarios array to update, using $ positional operator.
Finally, and this part should be self-explanatory: full object of new comment to add to the specified class.
It's also worth mentioning that if you're running into such deeply nested structure, perhaps it's worth thinking about spreading courses, classes, possibly even comments over separate MongoDB collections.
When nested documents are the way to go and when it's better to create separate collections can be actually tricky question to answer - here's nice presentation discussing this issue.

Update array value vs object value

How do you update the sku value within an array as in example "B". Should I go with A over B?
Option A - Object
Scheme
"data" : {
"products" : {
235099432:{
"product_id" : 101242538,
"sku" : "",
"variant_id" : 235099432
},
]
}
Update
db.col.update({
"data.products.235099432.variant_id": 235099432
}, {
$set: {
"data.products.235099432.sku": "ITM-RED-212"
}
});
Option B - Array
Scheme
"data" : {
"products" : [
{
"product_id" : 101242538,
"sku" : "",
"variant_id" : 235099432
},
]
}
You can use the $ position operator to identify the products array element to update that matches your filter:
db.col.update({
"data.products.variant_id": 235099432
}, {
$set: {
"data.products.$.sku": "ITM-RED-212"
}
});
My vote would be option B; the use of dynamic keys in option A can get very messy.

Resources