jellyx
(Nedim)
1
Hi everyone,
Is it possible to use elemMatch within filter?
This is an example of my data:
{
"_id" : ObjectId("5e6c26153facb910290f0869"),
"attributes" : [
{
"k" : "first_name",
"v" : "John"
},
{
"k" : "last_name",
"v" : "Doe"
},
{
"k" : "email",
"v" : "john.doe@example.net"
},
],
"events" : [
{
"event" : "add_to_cart",
"event_data" : [
{
"k" : "product_name",
"v" : "T-shirt"
},
{
"k" : "price",
"v" : 30
}
],
"created_at" : ISODate("2020-03-14T00:32:21.000Z")
},
],
"created_at" : ISODate("2020-03-14T00:32:21.000Z"),
}
I would like how it is possible to get users who had event “add_to_cart” with specific key/value attributes.
db.getCollection('clients').aggregate([
{
"$match": {
"deleted_at": {
"$exists": false
}
}
},
{
"$addFields": {
"event_count": {
'$size': {
"$filter" : {
"input" : "$events",
'as' : 'events',
'cond' : {
'$and': {
// How to add elemMatch here?**
}
}
}
}
}
}
},
])
How to combine $elemMatch and $filter?
Natac13
(Sean Campbell)
2
I am not 100% sure. However $elemMatch
would need to know the array field to operate on. As seen with the docs example
{ _id: 1, results: [ { product: "abc", score: 10 }, { product: "xyz", score: 5 } ] }
{ _id: 2, results: [ { product: "abc", score: 8 }, { product: "xyz", score: 7 } ] }
{ _id: 3, results: [ { product: "abc", score: 7 }, { product: "xyz", score: 8 } ] }
db.survey.find(
{ results: { $elemMatch: { product: "xyz", score: { $gte: 8 } } } }
)
I think you might be able to achomplish what you are after with the following.
{
"$addFields": {
"event_count": {
'$size': {
"$filter" : {
"input" : "$events",
'as' : 'events',
'cond' : {
'$and': [
{ '$$events.k': { $eq: something } },
{ '$$events.v': { $eq: something } }
]
}
}
}
}
}
}
Again I am not 100% sure. I just wanted to share some thoughts
jellyx
(Nedim)
3
Thank you for the answer.
Hmm, the problem is that it is possible to have another key-value array in v key. And another.
I also tried to use the following filter:
"$filter" : {
"input" : "$events",
"as" : "events",
'cond' : {
'$and': {
'$eq': [ '$$events.event.event_data.k', "product_name" ]
}
}
}
However, it doesn’t return anything. Zero results. Although there should be.
Natac13
(Sean Campbell)
4
If you used that exact example then the $and
is incorrect as it takes an array instead of an object.
See the docs
jellyx
(Nedim)
5
Unfortunately, I haven’t understood you.
This also does not work:
'$and': [
{'$eq': [ '$$events.event.event_data.k', "product_name" ]}
]
Natac13
(Sean Campbell)
6
Check out this example in the docs
db.inventory.aggregate(
[
{
$project:
{
item: 1,
qty: 1,
result: { $and: [ { $gt: [ "$qty", 100 ] }, { $lt: [ "$qty", 250 ] } ] }
}
}
]
)
See how there are 2 expressions in the $and
. If you only need one expression check then no need for the $and
operation
And I think you want '$$events.event_data.k'
as you are setting the events array to $$events
in the $filter
operation
jellyx
(Nedim)
7
There will be more filters, but I simplified it here. Yes, you’re right. I should be $$events.event_data.k
but still nothing:
"$filter" : {
"input" : "$events",
"as": "events",
"cond": { "$eq": [ "$$events.event_data.k", "product_name" ] }
}
This seems weird to me.