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.
Related
With Mongoose, I would like to be able to get a list of trainings by exercise _id parameter.
My training collection looks like this :
[
{
"_id": "617420adb9a7d7e02d591416",
"workout": {
"exercises": [
{
"_id": "61742066b9a7d7e02d5913ea",
"name": "Exercise 1"
}
],
"name": "Workout 1",
"_id": "617420a1b9a7d7e02d591401"
},
},
{
"_id": "617420b5b9a7d7e02d59141f",
"workout": {
"exercises": [
{
"_id": "61742066b9a7d7e02d5913ea",
"name": "Exercise 2"
}
],
"name": "Workout 2",
"_id": "617420a1b9a7d7e02d591401"
},
},
{
"_id": "6174226830610e43b0f6a283",
"workout": {
"exercises": [
{
"_id": "6174225630610e43b0f6a267",
"name": "Exercise 2"
}
],
"name": "Workout 3",
"_id": "6174226030610e43b0f6a275"
},
}
]
Based on MongoDB documentation I tried something like this :
this.trainingModel.find({
'workout.exercises._id': '61742066b9a7d7e02d5913ea',
});
This code returns an empty array. I was expecting to have two trainings (the two first of collection).
I also did this :
this.trainingModel.find({
'workout.exercises': { _id: '61742066b9a7d7e02d5913ea' },
});
But I also get an empty array as response.
I have just found the solution. As #turivishal said I had first to convert the string id to ObjectId. But then I also had to change the query like this :
this.trainingModel.find({
'workout.exercises._id': new Types.ObjectId('my_string_id'),
});
Apologies for the confusing title, I am not sure how to summarize this.
Suppose I have the following list of documents in a collection:
{ "name": "Lorem", "source": "A" }
{ "name": "Lorem", "source": "B" }
{ "name": "Ipsum", "source": "A" }
{ "name": "Ipsum", "source": "B" }
{ "name": "Ipsum", "source": "C" }
{ "name": "Foo", "source": "B" }
as well an ordered list of accepted sources, where lower indexes signify higher priority
sources = ["A", "B"]
My query should:
Take a list of available sources and a list of wanted names
Return a maximum of one document per name.
In case of multiple matches, the document with the most prioritized source should be chosen.
Example:
wanted_names = ['Lorem', 'Ipsum', 'Foo', 'NotThere']
Result:
{ "name": "Lorem", "source": "A" }
{ "name": "Ipsum", "source": "A" }
{ "name": "Foo", "source": "B" }
The results don't necessarily have to be ordered.
Is it possible to do this with a Mongo query alone? If so could someone point me towards a resource detailing how to accomplish it?
My current solution doesn't support a list of names, and instead relies on a Python script to execute multiple queries:
db.collection.aggregate([
{$match: {
"name": "Lorem",
"source": {
$in: sources
}}},
{$addFields: {
"order": {
$indexOfArray: [sources, "$source"]
}}},
{$sort: {
"order": 1
}},
{$limit: 1}
]);
Note: _id fields are omitted in this question for the sake of brevity
How about this: With $group we have $min operator which takes lower source
Note: If you prioritize as ['B', 'A'], use $max then
db.collection.aggregate([
{
$match: {
"name": {
$in: [
"Lorem",
"Ipsum",
"Foo",
"NotThere"
]
},
"source": {
$in: [
"A",
"B"
]
}
}
},
{
$group: {
_id: "$name",
source: {
$min: "$source"
}
}
},
{
$project: {
_id: 0,
name: "$_id",
source: 1
}
}
])
MongoPlayground
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
I am new to mongoDB. I am having some trouble in updating the records in mongoDB collection.
How to add elements into array likes into the embedded record
I have a embedded collection like:
{
"_id": "iL9hL2hLauoSimtkM",
"title": "Some Topic",
"followers": [
"userID1",
"userID2",
"userID3"
],
"comments": [
{
"comment": "Yes Should be....",
"userId": "a3123",
"likes": [
"userID1",
"userID2"
]
},
{
"comment": "No Should not be....",
"userId": "ahh21",
"likes": [
"userID1",
"userID2",
"userID3"
]
}
]
}
I want to update the record as
{
"_id": "iL9hL2hLauoSimtkM",
"title": "Some Topic",
"followers": [
"userID1",
"userID2",
"userID3"
],
"comments": [
{
"comment": "Yes Should be....",
"userId": "a3123",
"likes": [
"userID1",
"userID2",
"userID3" // How to write query to add this element.
]
},
{
"comment": "No Should not be....",
"userId": "ahh21",
"likes": [
"userID1",
"userID2",
"userID3"
]
}
]
}
Please provide the query to add the element shown in comment.
Thank you.
Two possibilities here:
Since you don't have an unique identifier for the comments, the only way to update an specific item on the comments array is to explicitly indicate the index you are updating, like this:
db.documents.update(
{ _id: "iL9hL2hLauoSimtkM"},
{ $push: { "comments.0.likes": "userID3" }}
);
If you add an unique identifier for the comments, you can search it and update the matched item, without worrying with the index:
db.documents.update(
{ _id: "iL9hL2hLauoSimtkM", "comments._id": "id1"},
{ $push: { "comments.$.likes": "userID3" }}
);
You can try $addToSet which adds elements to an array only if they do not already exist in the set.
db.topics.update(
{ _id: "iL9hL2hLauoSimtkM" },
{ $addToSet: { "comments.0.likes": "userId3" } }
)
Try this:
db.<collection>.updateOne(
{_id:"iL9hL2hLauoSimtkM",comments:{$elemMatch:{userId:'a3123'}}},
{$push:{'comments.$.likes':'userID3'}})
$ operator is equivalent to the filter
$ === {_id:"iL9hL2hLauoSimtkM",comments:{$elemMatch:{userId:'a3123'}}}
nevertheless, we are basically pushing "userID3" into
[1] the "likes" array
[2] inside the specified element === $
[3] which belonging to the "comments" array
Below is my mongodb structure
[
{
"_id": "com.android.angrybirds",
"rating": [
{
"user": "BBE74610BEE1A92784FDB",
"value": "1"
},
{
"user": "BBE74610BEE1A92784F",
"value": "5"
},
{
"user": "BBE74610BEE1A9784F",
"value": "5"
}
]
}
]
I want to group and count the unique ratings. I tried to use aggregate, group but it didn't work.
Expected output
[
{
"_id": "com.avatarrom.angrybirds",
"rating": [
{
"1": 1,
"5": 2
}
]
}
]
Like #RickyA said, your aggregation query would be interesting. What you need is the aggregate function in combination with the group operator. This post has a nice sample how you can do that.