query 2-level array in mongodb - mongodb

in MongoDB, I have many documents in 2-level array as below:
{
_id:1,
"toPerson": [
[
{
"userid": "test1"
},
{
"userid": "test2"
}
],
[
{
"userid": "test10"
},
{
"userid": "test11"
}
]
]
}
.....
{
_id:99,
"toPerson": [
[
{
"userid": "test2"
},
{
"userid": "test3"
}
],
[
{
"userid": "test100"
},
{
"userid": "test101"
}
]
]
}
Question is how to query all documents that have userid say test2 ?
Have tried:
col.find({'toPerson.userid':'test2'})
it's return nothing. also I have tried using aggregate but found maybe it's not the right direction.
Anyone can help with this?
UPDATE 1
Just read this post
Retrieve only the queried element in an object array in MongoDB collection
but it's different
Structure different: is {field:[ [{ }], [{ }], .... ]}, not { field:[ {}, {} ] }
I want to keep all returned documents structure untouched, $unwind(make toPerson to be 1-level array) or $$PRUNE(remove some fields) will change the structure returned.
UPDATE 2
What I want is to get following result in ONE statement:
col.find({ 'toPerson.0.userid':'test2' })
+ col.find({ 'toPerson.1.userid':'test2' })
+ ... ...
Is there any precise counterpart statement of above results combined together ?

You can query nested arrays like this using two levels of $elemMatch:
db.test.find({toPerson: {$elemMatch: {$elemMatch: {userid: 'test2'}}}})
The outer $elemMatch says match an array element of toPerson where the value passes the inner array $elemMatch test of an element matching {userid: 'test'}.

Related

MongoDB: Can't update in nested arrays

I've been trying to modify a value in multiple arrays for a few arrays and I can't find documentation on how to do this.
My collection looks like this
"rates": [
{
"category": "Web",
"seniorityRates": [
{
"seniority": "junior",
"rate": 100
},
{
"seniority": "intermediate",
"rate": 135
},
{
"seniority": "senior",
"rate": 165
}
]
}
]
I'm just trying to modify "junior" to "beginner", this should be simple.
Thanks to these answers:
How can I update a multi level nested array in MongoDB?
MongoDB updating fields in nested array
I've manage to write that python code (pymongo), but it doesn't works...
result = my_coll.update_many({},
{
"$set":
{
"rates.$[].seniorityRates.$[j].seniority" : new
}
},
upsert=False,
array_filters= [
{
"j.seniority": old
}
]
)
The path 'rates' must exist in the document in order to apply array updates.
It correspond to this command that doesn't work either
db.projects.updateMany({},
{
$set:
{
"rates.$[].seniorityRates.$[j].seniority" : "debutant"
}
},
{ arrayFilters = [
{
"j.seniority": "junior"
}
]
}
)
clone(t={}){const r=t.loc||{};return e({loc:new Position("line"in r?r.line:this.loc.line,"column"in r?r.column:......)} could not be cloned
What am I doing wrong ?
Any help would be very appreciated
The other option could be Sample
db.collection.update({},
{
$set: {
"rates.$[].seniorityRates.$[j].seniority": "debutant"
}
},
{
arrayFilters: [
{
"j.rate": { //As per your data, you can apply the condition o rate field to modify the level
$lte: 100
}
}
]
})
Or
The actual query should work Sample
db.collection.update({},
{
$set: {
"rates.$[].seniorityRates.$[j].seniority": "debutant"
}
},
{
arrayFilters: [
{
"j.seniority": "junior"
}
]
})
The same should work in python, a sample question
So I was just dumb here, I inverted two parameters so I didn't have the correct collection in the python code...
Thanks Gibbs for pointing out where the mistake was in the mongo command.
I will not delete this post as it can help other to know how to do this kind of queries.

Find document with only expected values allowed in nested array field in MongoDB

I'll start with the example as it's easier to explain for me.
[
{
"_id": 100,
"narr": [
{
"field": 1
}
]
},
{
"_id": 101,
"narr": [
{
"field": 1,
},
{
"field": 2
}
]
}
]
Goal is to find document exactly with values specified by me for a field.
Example:
for lookup = [1] find document with _id=100.
for lookup = [1,2] find document with _id=101.
So far I came up with (for second example with [1,2]):
db.col.find(
{
"narr": {
"$all": [
{
"$elemMatch": {
"field": {
"$in": [1, 2]
}
}
}
]
}
}
)
But it also includes document with _id=100. How can I make it perform strict match?
Building whole arrays won't work as there are multiple fields with unknown values in each nested structure.
Without considering duplication in the field and your input, you can simply do a find on narr.field. It is like performing search on an array with values from field.
db.collection.find({
$expr: {
$eq: [
"$narr.field",
[
1,
2
]
]
}
})
Here is the Mongo playground for your reference.
If duplication may happens, try to use $setEquals.
db.collection.find({
$expr: {
"$setEquals": [
"$narr.field",
[
1,
2
]
]
}
})
Here is the Mongo playground for your reference.

MongoDb aggregation - check if values in array are present in collection

I'm pretty new to MongoDb. I have a collection of some products, some of them contains an array of ids of other products in the same collection:
[
{
"id": 1,
"relatedProducts": [
"1", "2"
]
},
{
"id": 2,
"relatedProducts": [
"4", "5"
]
}
]
Problem is, not all of the products that are in that relatedProducts array are available in that collection.
I have to create an aggregation that will modify those arrays so only id of available products are present in it. So, for example, if product of id = 5 is not present in that collection, relatedProducts of object with id 2 above will have only one entry in the array ("4").
I recommend you first fetch all the product _id's, then update the documents accordingly.
Here's how I would do this:
const ids = await db.collection.distinct('id');
await db.collection.updateMany(
{
relatedProducts: {$nin: ids}
},
[
{
$set: {
relatedProducts: {
$setIntersection: [{$ifNull: ["$relatedProducts", []]}, ids]
}
}
}
]
)

MongoDB delete embedded documents through array of Ids

I am working on a Node.js application that is using a MongoDB database with Mongoose. I've been stuck in this thing and didn't come up with the right query.
Problem:
There is a collection named chats which contain embedded documents (rooms) as an array of objects. I want to delete these embedded documents (rooms) through Ids which are in the array.
{
"_id": "ObjectId(6138e2b55c175846ec1e38c5)",
"type": "bot",
"rooms": [
{
"_id": "ObjectId(6138e2b55c145846ec1e38c5)",
"genre": "action"
},
{
"_id": "ObjectId(6138e2b545c145846ec1e38c5)",
"genre": "adventure"
}
]
},
{
"_id": "ObjectId(6138e2b55c1765846ec1e38c5)",
"type": "person",
"rooms": [
{
"_id": "ObjectId(6138e2565c145846ec1e38c5)",
"genre": "food"
},
{
"_id": "ObjectId(6138e2b5645c145846ec1e38c5)",
"genre": "sport"
}
]
},
{
"_id": "ObjectId(6138e2b55c1765846ec1e38c5)",
"type": "duo",
"rooms": [
{
"_id": "ObjectId(6138e21c145846ec1e38c5)",
"genre": "travel"
},
{
"_id": "ObjectId(6138e35645c145846ec1e38c5)",
"genre": "news"
}
]
}
I am converting my array of ids into MongoDB ObjectId so I can use these ids as match criteria.
const idsRoom = [
'6138e21c145846ec1e38c5',
'6138e2565c145846ec1e38c5',
'6138e2b545c145846ec1e38c5',
];
const objectIdArray = idsRoom.map((s) => mongoose.Types.ObjectId(s));
and using this query for the chat collection. But it is deleting the whole document and I only want to delete the rooms embedded document because the ids array is only for the embedded documents.
Chat.deleteMany({ 'rooms._id': objectIdArray }, function (err) {
console.log('Delete successfully')
})
I really appreciate your help on this issue.
You have to use $pull operator in a update query like this:
This query look for documents where exists the _id into rooms array and use $pull to remove the object from the array.
yourModel.updateMany({
"rooms._id": {
"$in": [
"6138e21c145846ec1e38c5",
"6138e2565c145846ec1e38c5",
"6138e2b545c145846ec1e38c5"
]
}
},
{
"$pull": {
"rooms": {
"_id": {
"$in": [
"6138e21c145846ec1e38c5",
"6138e2565c145846ec1e38c5",
"6138e2b545c145846ec1e38c5"
]
}
}
}
})
Example here.
Also you can run your query without the query parameter (in update queries the first object is the query) like this and result is the same. But is better to indicate mongo the documents using this first object.

Mongodb: push element to nested array if the condition is met

I have the following collection:
{
"_id": 11,
"outerArray": [
{ "_id" : 21,
"field": {
"innerArray" : [
1,
2,
3
]
}
},
{ "_id" : 22,
"field": {
"innerArray" : [
2,
3
]
}
},
{ "_id" : 23,
"field": {
"innerArray" : [
2
]
}
}
]
}
I need to go through all documents in collection and push to innerArray new element 4, if innerArray already contains element 1 or element 3
I tried to do it this way, and few others, similar to this one, but it didn't work as expected, it only pushes to innerArray of first element of outerArray
db.collection.updateMany(
{ "outerArray.field.innerArray": { $in: [ 1, 3 ] } },
{ $push: { "outerArray.$.field.innerArray": 4} }
)
How to make it push to all coresponding innerArrays?
Problem here is your missunderstanding a copule things.
When you do "outerArray.field.innerArray": { $in: [ 1, 3 ] } into your query, your are not getting only innerArray where has 1 or 3. You are gettings documents where exists these arrays.
So you are querying the entire document.
You have to use arrayFilter to update values when the filter is match.
So, If I've understood you correctly, the query you want is:
db.collection.update(
{}, //Empty object to find all documents
{
$push: { "outerArray.$[elem].field.innerArray": 4 }
},
{
"arrayFilters": [ { "elem.field.innerArray": { $in: [ 1, 3 ] } } ]
})
Example here
Note how the first object into update is empty. You have to put there the field to match the document (not the array, the document).
If you want to update only one document you have to fill first object (query object) with values you want, for example: {"_id": 11}.