MongoDB query for two input arrays at same index? - mongodb

I have two arrays A and B of length n defined by the input,
fruit_ids = [{id: "id1"}, {id: "id2"}, {id:"id3"}];
fruit_names = [{name: "Orange"},{name: "Kiwi"},{name: "Banana"}]
and MongoDB documents
{ farm_id: "3344", fruits: [{name: "Orange", id:"id1"}, {name: "Kiwi", id:"id67"}]}
Now I want to write a Mongo query such that it pulls items from particular farm_id specified at array fruit_ids and fruit_names but at same index,
for example for the above input, I want for farm_id: 3344 {name: "Orange", id:"id1"} to get deleted.
Can anyone please help me.

You can use $pullAll operator to remove all the matching elements and build your update statement dynamically using below code:
var fruit_ids = [{id: "id1"}, {id: "id2"}, {id:"id3"}];
var fruit_names = [{name: "Orange"},{name: "Apple"},{name: "Banana"}];
var pullAll = {
$pullAll: { fruits: fruit_ids.map((id, index) => Object.assign(fruit_names[index], id)) }
}
db.col.update({ farm_id: 3344 }, pullAll)
This will only try to update the farm_id: 3344.

I was trying $pullAll as suggested by #mickl in his answer, but the thing is I had other fields inside my embedded documents and because $pullAll works only for exact matches, that's why I currently I am using $pull with $or on the array of embedded docs. I found this solution from this answer how-to-force-mongodb-pullall-to-disregard-document-order.
let arr = [{name: "Orange", id:"id1"}, {name: "Kiwi", id:"id67"}];
db.col.update(
{ farm_id: 3344 },
{ "$pull": { "fruits": { "$or": arr } }}
)

Related

How to combine $in and $elemMatch properly with MongoDB (PyMongo)

In my database, I've got data stored according to the following scheme:
{'_id': ...,
'names': [{'first': ...,
'last': ...},
{'first': ...,
'last': ...},
...
],
...
}
Now, in my program, I get a list of names according to the following scheme:
name_list = [(first_name1, last_name1), (first_name2, last_name2), ...]
What I want, is to find all documents where any of these combinations of first/last name found in name_list are contained in the names array.
If I'd have just one name to check (instead of a list), I'd use the following query:
query = {'names':
{'$elemMatch':
{'first_name': first_name,
'last_name': last_name}
}}
So I could supply this query for every name in the list, doing something like:
all_results = []
for first_name, last_name in name_list:
rv := # Result from query
# combine all_results and rv
But I feel like there should be a better way to do this.
A multi-elem match query could be created from name_list using $or and $elemMatch which works in a way to find the documents where any of those first/last combination matches.
Query: considering name_list to be
//[(first_name1, last_name1), (first_name2, last_name2), (first_name3, last_name3)]
db.collection.find({
$or: [
{
names: {
$elemMatch: {
first: "first_name1",
last: "last_name1"
}
}
},
{
names: {
$elemMatch: {
first: "first_name2",
last: "last_name2"
}
}
},
{
names: {
$elemMatch: {
first: "first_name3",
last: "last_name3"
}
}
}
]
});

Match multiple criteria inside an array [duplicate]

This question already has an answer here:
MongoDB : find value in Array with multiple criteria
(1 answer)
Closed 3 years ago.
I have the following:
offers: [
{user: 'jon', price: 200, selected: false},
{user: 'ted', price: 100, selected: true}
]
I am trying to do a match that will get all offer objects where user is ted and selected is true.
I tried the following:
$match: {
"offers.user": "ted"
"offers.selected": true
}
But this will give me the document if there is a ted and a selected true inside the array and not necessary that combination inside the same object.
You need to use $elemMatch query operator to match multiple criteria inside an array
{ "$match": {
"offers": {
"$elemMatch": {
"user": "ted"
"selected": true
}
}
}}
You want mongoose elemMatch function for your case.
query.elemMatch('comment', { author: 'autobot', votes: {$gte: 5}})
See the docs here:

Mongoose how to use positional operator to pull from double nested array with specific condition, and return new result

Suppose I have the following schema:
{
_id: ObjectId(1),
title: string,
answers: [
{
_id: ObjectId(2),
text: string,
upVotes: [
{
_id: ObjectId(3),
userId: ObjectId(4)
}
]
}
]
}
What I want is pull vote of a specific user from answer upvotes, and return the new update result.
For example, find a question with id 1, and get its specific answer with id 2, then from that answer pull my vote using userId inside upvotes.
I want to do it with a single findOneAndUpdate query
You can even use single $ positional with the $pull operator to update the nested array
db.collection.findOneAndUpdate(
{ "_id": ObjectId(1), "answers._id": ObjectId(2) },
{ "$pull": { "answers.$.upVotes": { "userId": ObjectId(4) }}}
)
I think I understood that you want to do a search in the specific array
db.collection.update(
{
"_id": "507f1f77bcf86cd799439011", // id field
"answers.upVotes._id":"507f1f77bcf86cd799439011" //id array
}
),{
"$set":{"answers.$.upVotes": {userId :"507f1f77bcf86cd799439011"}}},//edit
//use "addToSet" for add

Building mongo query

I have a model like this:
[{item: {
_id: 123,
field1: someValue,
price: {
[_id: 456,
field1: anotherValue,
type: []],
[_id: 789,
field1: anotherValue,
type: ['super']]
}
}]
I need to find an item by 3 parameters: item _id, price _id, and check if price type array is empty. And check it in one price field.
Model.findOneAndUpdate({_id: 123, "price._id": 456, "price.type": {size:0})
This query always returns item, cause search in different prices.
Model.findOneAndUpdate({_id: 123, price: {id: 456, type: {size:0})
This query returns error (cast array value or something like this).
tried to build query with $in, $and, but still getting an error
Use $elemMatch:
The $elemMatch operator matches documents that contain an array field
with at least one element that matches all the specified query
criteria.
db.inventory.find({
price: {
"$elemMatch": {
_id: 456,
type: {
$size: 0
}
}
}
})

mongo: update subdocument's array

I have the following schema:
{
_id: objectID('593f8c591aa95154cfebe612'),
name: 'test'
businesses: [
{
_id: objectID('5967bd5f1aa9515fd9cdc87f'),
likes: [objectID('595796811aa9514c862033a1'), objectID('593f8c591ba95154cfebe790')]
}
{
_id: objectID('59579ff91aa9514f600cbba6'),
likes: [objectID('693f8c554aa95154cfebe146'), objectID('193f8c591ba95154cfeber790')]
}
]
}
I need to update "businesses.likes" where businesses._id equal to a center value and where businesses.likes contains certain objectID.
If the objectID exists in the array, I want to remove it.
This is what I have tried and didn't work correctly, because $in is searching in all the subdocuments, instead of the only subdocument where businesses._id = with my value:
db.col.update(
{ businesses._id: objectID('5967bd5f1aa9515fd9cdc87f'), 'businesses.likes': {$in: [objectID('193f8c591ba95154cfeber790')]}},
{$pull: {'businesses.$.likes': objectID('193f8c591ba95154cfeber790')}}
)
Any ideas how how I can write the query? Keep in mind that businesses.likes from different businesses can have the same objectID's.