Update boolean value inside of nested array Mongoose - javascript

I have a Schema that holds an array of objects for comments and I would like to update the boolean value of the flagged comments accordingly, I have tried updateOne and aggregate but it isn't working out at this point, I have also tried to use $elemMatch but it isn't working.
The comment _id is being pulled from the front end element that has an ID that is the same as the id that needs to be pulled from MongoDB.
Comments Array within the question Schema:
comments: [
{
user: {
type: Object,
},
commentDate: {
type: Date,
default: Date.now()
},
flagged: {
type: Boolean,
default: false
},
flaggedDate:{type: Date},
comment: String,
}
],
function I tried to run last.
const id = req.params.id
const updateFlag = Question.updateOne(
{
comments: [
{
_id: id
}
]
},
{
$set: {
comments: [
{
flagged: req.body.flagged
}
]
}
}
)
Any help would be appreciated!

You can do it with positional operator - $:
db.collection.update({
"comments._id": "3"
},
{
"$set": {
"comments.$.flagged": true
}
})
Working example

Related

Mongodb find documents with given field value inside an array and its id in another array inside the same document

My data model:
{
_id: ObjectId,
persons:[{
_id: ObjectId,
name: String,
...
}],
relations: [{
type: String,
personId: ObjectId,
...
}],
...
}
Here's my issue:
I am trying to find documents where person's name is x and it's _id is inside the relations array (personId) with a given type.
Example:
My data:
[{
_id:"1",
persons:[{
_id:"1",
name: "Homer"
},
{
_id:"2",
name: "Bart"
}],
relations: [{
type:"House_Owner",
personId: 1,
}],
}]
Request_1:
Find all documents where "Homer" is the house owner
Result:
[{
_id:"1",
...
}]
Request_2:
Find all documents where "Bart" is the house owner
Result:
[]
Any help would be appreciated.
The only solution I see here is to do the find operation with the given name value and after that filter the mongodb result.
PS: I cannot change the existing data model
EDIT:
I found a solution to do this by using $where operator with a javascript function but I am not sure that's the most efficient way.
db.myCollection("x").find({
$where: function() {
for (const relation of this.relations) {
if(relation.type === "House_Owner") {
for (const person of this.persons) {
if(person.name === "Homer" && person._id.equals(relation.personId)) {
return true;
}
}
}
}
}
})
You can do something like this:
const requiredName="x"
const requiredId = "id"
await yourModel.find({$and:[{"relations.personId":requiredId },{"persons.name":requiredName}]})

Edit multiple objects in array using mongoose (MongoDB)

So I tried several ways, but I can't, I can modify several objects with the same key but I can't modify any with different keys, if anyone can help me is quite a complex problem
{
id: 123,
"infos": [
{ name: 'Joe', value: 'Disabled', id: 0 },
{ name: 'Adam', value: 'Enabled', id: 0 }
]
};
In my database I have a collection with an array and several objects inside which gives this.
I want to modify these objects, filter by their name and modify the value.
To give you a better example, my site returns me an object with the new data, and I want to modify the database object with the new object, without clearing the array, the name key never changes.
const object = [
{ name: 'Joe', value: 'Hey', id: 1 },
{ name: 'Adam', value: 'None', id: 1 }
];
for(const obj in object) {
Schema.findOneAndUpdate({ id: 123 }, {
$set: {
[`infos.${obj}.value`]: "Test"
}
})
}
This code works but it is not optimized, it makes several requests, I would like to do everything in one request, and also it doesn't update the id, only the value.
If anyone can help me that would be great, I've looked everywhere and can't find anything
My schema structure
new Schema({
id: { "type": String, "required": true, "unique": true },
infos: []
})
I use the $addToSet method to insert objects into the infos array
Try This :
db.collection.update({
id: 123,
},
{
$set: {
"infos.$[x].value": "Value",
"infos.$[x].name": "User"
}
},
{
arrayFilters: [
{
"x.id": {
$in: [
1
]
}
},
],
multi: true
})
The all positional $[] operator acts as a placeholder for all elements in the array field.
In $in you can use dynamic array of id.
Ex :
const ids = [1,2,..n]
db.collection.update(
//Same code as it is...
{
arrayFilters: [
{
"x.id": {
$in: ids
}
},
],
multi: true
})
MongoPlayGround Link : https://mongoplayground.net/p/Tuz831lkPqk
Maybe you look for something like this:
db.collection.update({},
{
$set: {
"infos.$[x].value": "test1",
"infos.$[x].id": 10,
"infos.$[y].value": "test2",
"infos.$[y].id": 20
}
},
{
arrayFilters: [
{
"x.name": "Adam"
},
{
"y.name": "Joe"
}
],
multi: true
})
Explained:
You define arrayFilters for all names in objects you have and update the values & id in all documents ...
playground

Remove Object from Array in MongoDB given ID

I am making an application that works with playlists. I am using MongoDB with mongoose and storing videos in each playlist via an array, like so:
{
_id: ObjectId("61ca1d0ddb66b3c5ff93df9c")
name: "Playlist A"
videos: [
{
title: "Video 1",
url: "www.YouTube.com/video1",
startTime: "20",
endTime: "40",
_id: ObjectId("61ca1d1ddb66b3c5ff93e0ba")
},
...
]
}
I want to be able to remove a video from a playlist based on the _id of a video. I have tried looking online for solutions but the solutions I've found don't work. This is what I am trying:
Playlist.updateOne(
{ _id: req.params.playlistId },
{ $pull: { videos: { _id: req.params.vidId } } }
)
When I run the code above and log the result I get the following (not sure if this is relevant):
{
acknowledged: true,
modifiedCount: 1,
upsertedId: null,
upsertedCount: 0,
matchedCount: 1
}
Please let me know if you need any more information this is my first time posting a question :)
This is a TypeError req.params.vidId returns a string and mongoose is looking for Type ObjectId. The solution is to convert the string literal (req.params.vidId) to an ObjectId, like so:
Playlist.updateOne(
{ _id: req.params.playlistId },
{ $pull: { videos: { _id: mongoose.Types.ObjectId(req.params.vidId) } } }
)

mongoose deleting and updating in array

I need to take array from my model, delete from it some days and push to it some other days. It looks something like deleteAndUpdate.
To sum up:
I need to take Car from database. Take reserved property (it's a array), then delete from reserved days from given list, and then add to reserved days from other given list.
My model look:
const CarSchema = mongoose.Schema({
mark:{
type: String,
required: true,},
model:{
type: String,
required: true,},
price:{
type: Number,
required: true,},
available: {
type: Boolean,
required: true,},
reserved:{
type:[Date],
},
pic_1:{
type:String,
required:true,
},
pic_2:{
type:String,
required:true,
},
},
{ collection: 'cars' }
)
I take car by: var car= await Car.findById(carID); and then i need to do sth like that:
car['reserved'].deleted(old_days);
car['reserved'].push(new_days;
car.save();
Could someone help me?
Update can't allow multiple operation at a time in same field, It will throw multiple write error and would create a conflict at your field,
Regular update:
If you want to do it by regular update query you have to do separate do 2 queries,
Delete days: If you want to delete multiple days use $pullAll, and for single you can use $pull
var old_days = [new Date("2021-04-24"), new Date("2021-04-25")];
await Car.updateOne({ _id: carID }, { $pullAll: { reserved: old_days } });
Add days: if you want to add multiple days you can use $push with $each, and for single you can use just $push,
var new_days = [new Date("2021-04-26"), new Date("2021-04-27")];
await Car.updateOne({ _id: carID }, { $push: { reserved: { $each: new_days } } });
Update with aggregation pipeline:
If you are looking for single query you can use update with aggregation pipeline starting from MongoDB 4.2,
$filter to iterate loop of reserved array and remove old days
$concatArrays to concat reserved array with new days
var old_days = [new Date("2021-04-24"), new Date("2021-04-25")];
var new_days = [new Date("2021-04-26"), new Date("2021-04-27")];
await Car.updateOne(
{ _id: carID },
[{
$set: {
reserved: {
$filter: {
input: "$reserved",
cond: { $not: { $in: ["$$this", old_days] } }
}
}
}
},
{
$set: {
reserved: {
$concatArrays: ["$reserved", new_days]
}
}
}]
);
Playground
To remove old item from array you can use $pull
car.update(
{ _id: carID },
{ $pull: { 'reserved': old_days } }
);
You can use $unset to unset the value in the array (set it to null), but not to remove it completely.
To add the item new_days in array, You can either use $push or $addToSet
car.update(
{ _id: carID },
{ $push: { 'reserved': new_days } }
);

How to conditionally add a field based on match a field with an array Mongo

I'm trying to create a pipeline to add a field based in a condition:
I have a field called helpful which is an array that will contain a list of id's, what I want to do is add a field depending if a given ID is insided that array
an example of the data structure may be this:
{
helpful: [ 5ecd62230a180f0017dc5342 ],
verifiedPurchase: false,
_id: 5f789010e07e4033342c7307,
title: 'text',
body: 'text',
rating: 3,
user: {
_id: 5ecd62230a180f0017dc5342,
name: 'store11',
picture: 'pictureurl'
},
replies: [],
updatedAt: 2020-10-03T18:04:48.026Z,
createdAt: 2020-10-03T14:52:00.410Z,
helpfulCount: 1,
helpfulForMe: false
},
I already tried with this pipeline
{
$addFields:{
helpfulForMe: {
$cond: {
if: {"$in":[user, "$helpful"] } ,
then: true,
else: false,
}
}
}
},
and this one
"$addFields": {
"helpfulForMe" : {
"$in":[
['5ecd62230a180f0017dc5342'], "$helpful"
]
}
}
},
but both returned false even when I set a matching ID
I hope to get a good fix from you guys. Thanks
You can try if your input is array of ids,
$reduce to iterate loop of helpful array and check condition if id in user array then return true otherwise false
let user = ["5ecd62230a180f0017dc5342"];
{
$addFields: {
helpfulForMe: {
$reduce: {
input: "$helpful",
initialValue: false,
in: {
$cond: [{ $in: ["$$this", user] }, true, "$$value"]
}
}
}
}
}
Playground

Categories

Resources