How to find document that contains array with two equal values? - mongodb

I have chats's collection with participants array
[{
"_id": ObjectId("5d12b2a10507cfe0bad6d93c"),
"participants": [{
"_id": ObjectId("5ce4af580507cfe0ba1c6f5b"),
"firstname": "John",
"lastname": "Anderson",
"icon": "/assets/images/avatars/small/2.jpg"
},
{
"_id": ObjectId("5ce4af580507cfe0ba1c6f5b"),
"firstname": "John",
"lastname": "Anderson",
"icon": "/assets/images/avatars/small/2.jpg"
}
]
}, {
"_id": ObjectId("5d1124a50507cfe0baba7909"),
"participants": [{
"_id": ObjectId("5ce4af580507cfe0ba1c6f5b"),
"firstname": "John",
"lastname": "Anderson",
"icon": "/assets/images/avatars/small/2.jpg"
},
{
"_id": ObjectId("5ce54cb80507cfe0ba25d74b"),
"firstname": "Milosh",
"lastname": "Jersi",
"icon": "/assets/images/avatars/small/3.jpg"
}
]
}]
I fetch it by
req.db.collection('chats').findOne({'participants._id': {$all: [req.userID, new mongo.ObjectID(req.params.to)]}});
where userID is also ObjectID and equals.
Usually it have different participants, but our user can also send messages to itself, is allowed option in many social networks.
So in this situation, our user "John Anderson" sent message to himself and we inserted chat document for it.
And now i have problem, how to get document with equal array values
{'participants._id': { '$all': [ 5ce4af580507cfe0ba1c6f5b, 5ce4af580507cfe0ba1c6f5b] }}
// return every chat contains our id in atleast one field, but we need both to be equal
// same for $in
{'participants._id': { '$eq': [ 5ce4af580507cfe0ba1c6f5b, 5ce4af580507cfe0ba1c6f5b] }}
// return nothing
what else can I do ?

you can achieve this with the aggregation framework, using a $group stage. First, group by chat._id and use $addToSet to keep only unique users in a new array, ant then add a filter to keep only the documents with one participant:
db.collection.aggregate([
{
"$unwind": "$participants"
},
{
"$group": {
"_id": "$_id",
"participants": {
"$addToSet": "$participants._id"
}
}
},
{
"$match": {
"participants": {
"$size": 1
}
}
}
])
result:
[
{
"_id": ObjectId("5d12b2a10507cfe0bad6d93c"),
"participants": [
ObjectId("5ce4af580507cfe0ba1c6f5b")
]
}
]
you can try it online: mongoplayground.net/p/plB-gsNIxRd

Related

Delete objects that met a condition inside an array in mongodb

My collection has array "name" with objects inside. I need to remove only those objects inside array where "name.x" is blank.
"name": [
{
"name.x": [
{
"_id": "607e7fcca57aa56e2a06b57b",
"name": "abc",
"type": "123"
}
],
"_id": {
"$oid": "62232cd70ce38c5007de31e6"
},
"qty": "1.0",
"Unit": "pound,lbs"
},
{
"name.x": [
{
"_id": "607e7fcca57aa56e2a06b430",
"name": "xyz",
"type": "123"
}
],
"_id": {
"$oid": "62232cd70ce38c5007de31e7"
},
"qty": "1.0",
"Unit": "pound,lbs"
},{
"name.x": []
,
"_id": {
"$oid": "62232cd70ce38c5007de31e7"
},
"qty": "1.0",
"Unit": "pound,lbs"
}
I tried to get all the ids where name.x is blank using python and used $pull to remove objects base on those ids.But the complete array got deleted.How can I remove the objects that meet the condition.
Think MongoDB update with aggregation pipeline meets your requirement especially to deal with the field name with ..
$set - Update the name array field by $filter name.x field is not an empty array.
db.collection.update({},
[
{
$set: {
name: {
$filter: {
input: "$name",
cond: {
$ne: [
{
$getField: {
field: "name.x",
input: "$$this"
}
},
[]
]
}
}
}
}
}
],
{
multi: true
})
Sample Mongo Playground

MongoDB Aggregation - Filter array with another array

{
"_id": {
"$oid": "5f8f067ecf44854d4c3b5286"
},
"photo": "",
"followers": [
{
"$oid": "5f8f26f8cf44854d4c3b528f"
},
{
"$oid": "5f9f1984cf44854d4c3b5292"
},
{
"$oid": "5f8f06c9cf44854d4c3b528e"
},
{
"$oid": "604b1d0649a2052e912f9c3f"
},
{
"$oid": "5f8f0688cf44854d4c3b5287"
},
{
"$oid": "62371c3b8fabe53cf4386b1f"
}
],
"following": [
{
"$oid": "5f9f1984cf44854d4c3b5292"
},
{
"$oid": "5f8f26f8cf44854d4c3b528f"
},
{
"$oid": "5f8f06c9cf44854d4c3b528e"
}
],
"email": "johndoe#test.com",
"firstname": "John",
"lastname": "Doe",
"username": "JohnDoe01",
"__v": 0
}
I am trying to get a list of followers from a specific user. I have a list of blocked users, so I need to exclude those users from the followers list.
For eg:
let blockedUsers = ['5f8f26f8cf44854d4c3b528f', '5f9f1984cf44854d4c3b5292'];
FYI : followers also user objects
Let me know any further details needed. Thanks in advance.
You can use $filter to filter the follower (id) that is not in the blocked list.
While you perform the comparison, make sure:
Option 1: Value(s) in the blocked list cast to ObjectId
or
Option 2: Cast the follower to string
Must compare values with the same type.
db.collection.aggregate({
$set: {
followers: {
$filter: {
input: "$followers",
cond: {
$not: {
$in: [
{
$toString: "$$this" // Or "$$this._id" for user Object
},
[
"5f8f26f8cf44854d4c3b528f",
"5f9f1984cf44854d4c3b5292"
]
]
}
}
}
}
}
})
Sample Mongo Playground

MongoDB query double nested array with matching sets

Being not familiar with Mongo and still progressing I came accross a problem I can't think to fix (and I don't know if it's feasible)
I have an Event document whose structure looks like this:
{
"_id": "6138451fb3a7d9564a0229fd"
"title": "Event 1",
"cohortsGroups": [
[
{
"_id": "6124beef59d728c82088fd59",
"name": "2022",
"type": "promotion"
},
{
"_id": "6124bf2159d728c82088fd60",
"name": "Toronto",
"type": "city"
}
],
[
{
"_id": "6124beef59d728c82088fd57",
"name": "2024",
"type": "promotion"
},
{
"_id": "6124bf2159d728c82088fd68",
"name": "Tokyo",
"type": "city"
}
],
]
},
{
"_id": "6138451fb3a7d9564a0229fe"
"title": "Event 2",
"cohortsGroups": [
[
{
"_id": "6124beef59d728c82088fd59",
"name": "2022",
"type": "promotion"
}
]
]
},
{
"_id": "6138451fb3a7d9564a0229fh"
"title": "Event 3",
"cohortsGroups": [
[
{
"_id": "6124beef59d728c82088fd21",
"name": "2022",
"type": "promotion"
},
{
"_id": "6124beef59d728c82088fd43",
"name": "Amsterdam",
"type": "city"
}
]
]
}
As you can see the field cohortsGroups is a double array of Objects. I would like to retrieve those events based on my user's object who possess also an array (simple) of cohorts
So for example let's say my user looks like this:
{
"firstName": "John",
"lastName": "Doe",
"cohortsRef": [
{
"_id": "6124beef59d728c82088fd59",
"name": "2022",
"type": "promotion"
},
{
"_id": "6124bf2159d728c82088fd60",
"name": "Toronto",
"type": "city"
}
]
}
To make it simple I would like to retrieve an event only if one of the set of cohorts in in his cohortsGroups have his cohorts all presents in the user object.
Taking that in mind and the above example I would only be able to retrive Event 1 and Event 2.
I can't retrieve Event 3 because even tho I have the Cohort 2022 in my user, it's paired with the Cohort Amsterdam which is not present in my user's cohorts, (eq: none of the cohort subarrays sets have their values entirely present in my user's cohorts).
I really hope someone can give me a hand on that problem, so far I've tried to map all the user's cohorts ID in an array and query by $elemMatch
Events.find({ cohortsGroups: { $elemMatch: { $elemMatch: { _id: { $in: [ '6124beef59d728c82088fd59', '6124bf2159d728c82088fd60' ] } } } } })
But this solution just retrieves every event that have a subarray cohort matching, it doesn't take into account the sets, so in this case it would also retrieve Event 3 - because 2022 is present - but it's paired with the cohort Amsterdam which is wrong.
Let me know if I wasn't clear enough, any help would be appreciated. At least to know if it's something doable as a mongo query.
Thanks a lot for reading !
This should work:
db.events.find({ cohortsGroups: { $elemMatch: { $not: {$elemMatch: { _id: { $nin: [ '6124beef59d728c82088fd59', '6124bf2159d728c82088fd60' ] } } } } } })
The outer $elemMatch, matches any document where any array in cohortsGroups matches the inner condition.
The inner condition
{ $not: {$elemMatch: { _id: { $nin: [ '6124beef59d728c82088fd59', '6124bf2159d728c82088fd60' ] } } } } }
is using a double negative with $not and $nin to find subarrays that have no element with an _id except those that you are searching for.

Find documents that share one key but differ in another

I have a mongodb collection that is resembles
{"dept":"A" , "email":"bob#example.com", "userID": "1"}
{"dept":"A" , "email":"bob#example.com", "userID": "1"}
{"dept":"A" , "email":"bob#example.com", "userID": "2"} <<< "bad" record
{"dept":"A" , "email":"alice#example.com", "userID": "3"}
{"dept":"B" , "email":"bob#example.com", "userID": "4"}
{"dept":"B" , "email":"kevin#example.com", "userID": "5"}
The constraint is that an email must only have a single userID per department.
How would I query the table to find which emails have multiple userIDs within a department? Mongo 4.4+
You have to use two $group pipeline stages to filter and find records with multiple entries.
db.collection.aggregate([
{
"$group": {
"_id": {
"dept": "$dept",
"email": "$email",
"userID": "$userID",
},
"individualCount": {
"$sum": 1
}
},
},
{
"$group": {
"_id": "$_id.email",
"userIDs": {
"$addToSet": "$_id.userID"
},
"dept": {
"$addToSet": "$_id.dept"
},
"totalRecordsCount": {
"$sum": "$individualCount"
},
"totalDuplicCounts": {
"$sum": 1
},
},
},
{
"$match": {
"totalDuplicCounts": {
"$gt": 1
}
},
},
])
Mongo Playground Sample Execution

Add conditional and in array of object, mongodb

I have a document like this
{
"_id": {
"$oid": "5c7369826023661073802f63"
},
"participants": [
{
"id": "ABC",
"nickname": "USER1",
},
{
"id": "DEF",
"nickname": "USER2",
}
]},... etc, et
I want to find the record that has the two ids that you provide
I try with this.
moodel.aggregate([
{
$match:{'participants.id':idOne}
},{
$project:{
list:{
$filter:{
input:'$list',
as:'item',
cond: {$eq: ['$$item.participants.id', idTwo]}
}
},
}
}
])
but the result is:
[ { _id: 5c7369826023661073802f63, list: null }]
I want it to return only the record that match the two ids.
use $elematch and $in
https://docs.mongodb.com/manual/reference/operator/query/elemMatch/
https://docs.mongodb.com/manual/reference/operator/query/in/
db.moodel.find({"participants": {$elemMatch: {id: {$in: [idOne, idTwo]}}}})