**Hi guys, I really need your help. In mongoDB, I have a users collection where each user has a "friends" array, consisting of other users' _id s.
I am finding a user, getting the array of that user's friends and trying to find every other user with the _id s that are in that friends array;
Then I'm trying to check if the found users have "notifications" array's length more than or equal to 50. If that's the case, I want to remove the first element from that array and then push a document in it, else I want to just push a document in the "notifications" array.
But it doesn't work, I am trying to do this:**
User.updateMany(
{
'_id': {
$in: usersFriends.map(userId => new ObjectId(userId))
}
},
{
$cond: [
{ $gte: [ {$size: ['$notifications']}, 50 ] },
{
$pop: {'$notifications': 1},
$push: {"$notifications": NOTIF}
},
{ $push: {"$notifications": NOTIF} }
],
}
)
.then(DATA => {
res.status(201).json({
data: data,
DATA: DATA
})
})
Please someone help me.
Related
I am working on an app that uses MongoDB (I use Mongoose) as its database.
I have a question, suppose I have this kind of schema:
[{
"user_id":"2328292073"
"username":"Bob",
"subscriptions":[
{
"id":"38271281,
"payments":[
{
"id":"00001",
"amount":"1900"
},
{
"id":"00002",
"amount":"2000"
},
{
"id":"00003",
"amount":"3000"
}
]
}
]
}]
In my case I want to get the payments array for subscription with id = '38271281' of user with id '2328292073', but I just want to retrieve the payment array, nothing else
My query is the following:
Mongoose.findOne({
"user_id": "2328292073",
"subscriptions.id": "38271281"
},
{
"subscriptions.payments": 1
})
But I get the entire document of subscriptions. How can i get the payment array only?
you can try using unwind if you want filteration from db only.
Mongoose.aggregate([
{
'$match': {
'user_id': '2328292093'
}
}, {
'$unwind': {
'path': '$subscriptions'
}
}, {
'$match': {
'subscriptions.id': '38271281'
}
}
])
if you will have multiple documents having same subscription id then you have to group it .
using code level filter function can also be one another approach to do this .
You can try aggregation operators in projection in find method or also use aggregation method,
$reduce to iterate loop of subscriptions and check the condition if id matched then return payment array
db.collection.find({
"user_id": "2328292073",
"subscriptions.id": "38271281"
},
{
payments: {
$reduce: {
input: "$subscriptions",
initialValue: [],
in: {
$cond: [
{ $eq: ["$$this.id", "38271281"] },
"$$this.payments",
"$$value"
]
}
}
}
})
Playground
I have got a data structure:
{
field: 1,
field: 3,
field: [
{ _id: xxx , subfield: 1 },
{ _id: xxx , subfield: 1 },
]
}
I need to update a certain element in the array.
So far I can only do that by pulling out old object and pushing in a new one, but it changes the file order.
My implementation:
const product = await ProductModel.findOne({ _id: productID });
const price = product.prices.find( (price: any) => price._id == id );
if(!price) {
throw {
type: 'ProductPriceError',
code: 404,
message: `Coundn't find price with provided ID: ${id}`,
success: false,
}
}
product.prices.pull({ _id: id })
product.prices.push(Object.assign(price, payload))
await product.save()
and I wonder if there is any atomic way to implement that. Because this approach doesn't seem to be secured.
Yes, you can update a particular object in the array if you can find it.
Have a look at the positional '$' operator here.
Your current implementation using mongoose will then be somewhat like this:
await ProductModel.updateOne(
{ _id: productID, 'prices._id': id },//Finding Product with the particular price
{ $set: { 'prices.$.subField': subFieldValue } },
);
Notice the '$' symbol in prices.$.subField. MongoDB is smart enough to only update the element at the index which was found by the query.
I am having trouble with the "$in" operator in Mongoose. At a high level I have a User schema, and one of the fields is an array of a Card schema. Within the Card schema there is a 'score' field. I would like to update the 'score' field based on a list of Card ids. Here is what I am trying to use:
User.updateMany(
{
"_id": userId,
"cards._id": {
"$in": cardIds
}
},
{ $inc: {"cards.$.score": 1 }},
(err) => {console.log(err)}
)
When I run this code, only the first Card in the cardIds array is updated instead of all of them. Any idea why this isn't working? Thanks.
You need to use arrayFilters in .updateMany() , Try this query :
User.updateMany({
"_id": userId
},
{ $inc: { "cards.$[element].score": 1 } },
{ arrayFilters: [{ "element._id": { "$in": cardIds } }] },
(err) => {}
)
I have a user with various post ID's inside of my mongodb database, I am using mongoose to talk to it.
this is the user object
[
{
"premium": true,
"max_posts": 55,
"posts_made": 52,
"posts": [
"5e10046c0be4f92228f6f532",
"5e1005a9dceb1344241c74c5",
"5e100753a6cfcb44d8f1fa09",
"5e1007bea6cfcb44d8f1fa0a",
"5e1008149324aa1d002a43be",
"5e1009562826a308a0812e92",
"5e100a625e6fcb2c90a07bec",
"5e157143536d6e04a80651bd",
"5e1e320dc749f23b189ccef7",
"5e1e3273546d55384c3a975c",
"5e1e340183d0b0080816cedd",
"5e1e368bd921f3194c22b3d2",
"5e1e3732d921f3194c22b3d3",
"5e1e3a6f9b3017189cff0fe2",
"5e1e3c1a8c38f11c60354052",
"5e1e9ab208d0a5416828d0a3"
],
"_id": "5e0fe3f33c2edb2f5824ddf2",
"email": "user#gmail.com",
"createdAt": "2020-01-04T01:01:39.840Z",
"updatedAt": "2020-01-15T04:53:08.987Z",
"__v": 16
}
]
So, I make a request to the database using express, and I try to filter the array, using an id of one post, then I ask express to save that modified user model...
router.delete('/testing', (req,res,next) =>{
userModel.findOne({ email: req.body.author }, function(error, user) {
user.posts.filter(item => item != req.body.postid)
user.save((err) => {
console.log(err);
});
res.json(user)
});
});
my request in postman :
As you can see, the item is still there in that array... checking the console.log.
Please Advise as I am having doubts, thanks.
You no need to find & update the document of user, which makes two DB calls, plus .filter(), try this :
router.delete('/testing', (req, res, next) => {
userModel.findOneAndUpdate({ email: req.body.author},
{ $pull: { "posts": req.body.postid } }, { new: true }, function (error, user) {
res.json(user);
});
});
Here we're using .findOneAndUpdate() as it returns the updated user document which you need to send back.
This is how I would do it using $pull operator.
The $pull operator removes from an existing array all instances of a value or values that match a specified condition.
userModel.update(
{email: req.body.author},
{ $pull: { posts: { $in: [ req.body.postid ] } } },
{ multi: true }
)
For now it seems like you are passing single postid in request body. In future if you needed to delete multiple posts at the same time, you can use the same query by just replacing { $in: [ req.body.postid ] } with { $in: [ ...req.body.postid ] }
I have collection like this :
{
"_id" : ObjectId(),
"user_id":"10"
"movie_rate":[
{
rate:2,
movie_id:"120"
},
{
rate:null,
movie_id:"230"
},
]
}
I want to update movie rate array element with movie id and I build a query for doing this:
db.rates.update({
user_id: data.user_id,
"movie_rate.movie_id": data.movie_id
}, {
$set: {
"movie_rate.$.rate": data.rate
}
}
All movie id are unique, so there is just one element in the movie rate array that I wanted to update; however my update query take to much time to execute, I have 7000 document and each document have movie rate array which length is 3700.
I found out another solution which in the first place it seems to be very awful idea,I solve this problem in three query first I find document with find query and user id,then I loop over movie rate array and find out the index of that element, I wanted to update next I pull the element from array with movie id and at last I push document in the array with it's position that I found out in the find query my awful solution was significantly faster than the first one.
Here my pull query:
db.rates.update(
{
user_id: data.user_id
},
{
$pull: {
movie_rate: {
movie_id: data.movie_id
}
}
}
and here is my push query:
db.rates.update(
{
user_id: data.user_id
},
{
$push: {
movie_rate: {
$each: [{
'rate': data.rate,
'movie_id': data.movie_id
}],
$position: index
}
}
}
So why my second solution is faster than my first one?