Mongo if inside $match and $or [duplicate] - mongodb

This question already has answers here:
mongo in() clause sort by most matches
(2 answers)
Closed 9 months ago.
I've been stuck with this for a quite while.
I want to filter specials.name field based on two inputs from my form - select and input field. The problem is, whatever I tried, it always chooses on of it.
Is there any way to put if, else block inside $or to make it work?
This is the last thing that I tried, and now it works always on searchInput, which is input field, it does not react on changes in select menu.
{
$match: {
$or: [
{ 'specials.name':{$in :[searchSpecials, searchInput]}},
]
}
}
const searchSpecials = req.body.searchSpecials
const searchInput = req.body.search

If the two inputs are strings, this works as expected:
db.collection.aggregate([
{
$match: {"specials.name": {$in: ["Malinda", "Joseph"]}}
}
])
and returns:
[
{
"_id": ObjectId("5a934e000102030405000000"),
"specials": {
"name": "Malinda"
}
},
{
"_id": ObjectId("5a934e000102030405000002"),
"specials": {
"name": "Joseph"
}
}
]
As you can see here, on the playground.
No need for the $or, since the $in will return all documents that have specials.name which is included in the list of options.

Related

MongoDB $elemMatch comparison to field in same document

I'm wanting to create an aggregation step to match documents where the value of a field in a document exists within an array in the same document.
In a very worked example (note this is very simplified; this will be fitting into a larger existing pipeline), given documents:
{
"_id":{"$oid":"61a9085af9733d0274c41990"},
"myArray":[
{"$oid":"61a9085af9733d0274c41991"},
{"$oid":"61a9085af9733d0274c41992"},
{"$oid":"61a9085af9733d0274c41993"}
],
"myField":{"$oid":"61a9085af9733d0274c41991"} // < In 'myArray' collection
}
and
{
"_id":{"$oid":"61a9085af9733d0274c41990"},
"myArray":[
{"$oid":"61a9085af9733d0274c41991"},
{"$oid":"61a9085af9733d0274c41992"},
{"$oid":"61a9085af9733d0274c41993"}
],
"myField":{"$oid":"61a9085af9733d0274c41994"} // < Not in 'myArray' collection
}
I want to match the first one because the value of myField exists in the collection, but not the second document.
It feels like this should be a really simple $elemMatch operation with an $eq operator, but I can't make it work and every example I've found uses literals. What I've got currently is below, and I've tried with various combinations of quotes and dollar signs round myField.
[{
$match: {
myArray: {
$elemMatch: {
$eq: '$this.myField'
}
}
}
}]
Am I doing something very obviously wrong? Is it not possible to use the value of a field in the same document with an $eq?
Hoping that someone can come along and point out where I'm being stupid :)
Thanks
You can simply do a $in in an aggregation pipeline.
db.collection.aggregate([
{
"$match": {
$expr: {
"$in": [
"$myField",
"$myArray"
]
}
}
}
])
Here is the Mongo playground for your reference.

How to deselect one object in array MongoDB? [duplicate]

This question already has answers here:
Retrieve only the queried element in an object array in MongoDB collection
(18 answers)
Closed 3 years ago.
In my situation I just need my result but without my objectID in my array.
This is my method :
return Room.findOne(
{
_id: idRoom,
participants: {$elemMatch: {$ne: this.currentUser.profile}},
},
{
'participants.$': 1,
}
)
With elementMatch, the problem is when you found the object, only the first object is returned.
This is my result :
"result": {
"_id": "5da5e77f51e08708b79565e8",
"participants": [
"5da4d5b40cc94f04a7aaad40"
],
And this is the real result I need
"result": {
"_id": "5da5e77f51e08708b79565e8",
"participants": [
"5da4d5b40cc94f04a7aaad40"
"fwnert9248yrhnqwid13982r" // I have another participants
],
And my model is just like this :
const RoomSchema = new Schema({
participants: [{type: Schema.Types.ObjectId,ref: 'Profile'}],
...
}, options)
For others reasons, I can't use aggregate, thank you if you have the solution
So I think you are trying to shape a resultset in mongo with the findOne() method, and any use of the aggregation pipeline framework is out of the question and unavailable for other reasons.
I am not sure this is possible. I believe you will need to perform multiple steps to achieve your desired results. If you can use aggregation pipeline framework here is a pipeline to suit the desired results (I believe)...
db.Room.aggregate(
[
{
"$match": { _id: ObjectId(idRoom)}
},
{
$project: {
"participants": {
$filter: {
input: "$participants",
as: "participant",
cond: {$ne: ["$$participant", this.currentUser.profile] }
}
}
}
}
]
)
...but if you cannot use aggregation pipeline then here is a mongoshell script that accomplishes the task in several steps. The strategy is to capture the whole document by _id then remove the data element from the array then echo the results...
var document = db.Room.findOne( { _id: ObjectId("5da64a62cd63abf99d11f210") } );
document.participants.splice(document.participants.indexOf("5da4d5b40cc94f04a7aaad40"), 1);
document;

Mongo Query in Nested Json Array [duplicate]

This question already has answers here:
Retrieve only the queried element in an object array in MongoDB collection
(18 answers)
Closed 4 years ago.
A document in my collection looks like below:
{
"_id":"<uuid>",
"tests":[
{
"min":5,
"max":20
},
{
"min":15,
"max":35
}
]
}
Now, I want to find all the tests in which min >= 5.
db.coll.aggregate([
{ $match: { 'tests.min': {$gte : 5}} },
{ '$unwind': "$tests" }
]);
the above query somehow doesnt return the correct results.
You do not need to write a aggregate query for this. Use the $elemMatch operator for this. Your query will look like as shown
db.coll.find({
tests: {
$elemMatch: {
min: {
$gte: 5
}
}
}
})
The above query will return the desired result.
For more details visit
$elemMatch (query)

Find the count of all the matching elements in an array [duplicate]

This question already has answers here:
Mongodb count all array elements in all objects matching by criteria
(2 answers)
Closed 4 years ago.
I need to find the count of all the matching array elements and count = 0 if the nested array do not contain values.
Here is my data entity structure.
{
name:A,
issues:[1,2,3,4]
}
{
name:B,
issues:[1,2]
}
{
name:C,
issues:[3,4]
}
If user search for issues:[1,2], I want my result set to look like
[{
name:A,
count:2
}
{
name:B,
count:2
}
{
name:C,
count:0
}]
I am using below query to achieve this but it only returns me result
[{
name:A,
count:2
}
{
name:B,
count:2
}]
which definitely I know because of the $match I am doing
{'$unwind':'$issues'}
,{'$match':{'allissues': {$in: p.issues? p.issues.map(Number):[]}}}
,{ '$group' :{_id:'$_id', name :{ $first: '$name' },count: { $sum: 1 }} }'
Given that issues variable is the array input by users, you do not need to use a three-stages aggregation like above to get the result. You just need to find the intersection of users input and issues field of each document, then get length of the result arrays. This code will do the job:
db.col.aggregate([{
$project: {
count: {
$size: {
$setIntersection: [issues, "$issues"]
}
}
}
}])

MongoDB Aggregation Framework: $project: use a value of a doc as the name of a key [duplicate]

This question already has answers here:
count array occurrences across all documents with mongo
(2 answers)
Closed 7 years ago.
I have the following subdocument:
{
"id":1,
"url":"mysite.com",
"views":
[
{"ip":"1.1.1.1","date":"01-01-2015"},
{"ip":"2.2.2.2","date":"01-01-2015"},
{"ip":"1.1.1.1","date":"01-01-2015"},
{"ip":"1.1.1.1","date":"01-01-2015"}
]
}
and the following query so far:
db.collection.aggregate([
{
"$unwind": "$views"
},
{
"$group": {
"_id": "$views.ip",
"count": {
"$sum": 1
}
}
}
])
that returns the following result:
[
{
"_id":"2.2.2.2",
"count":1
},
{
"_id":"1.1.1.1",
"count":3
}
]
I would like to achieve the following output result, or quite similar:
[
{
"2.2.2.2": 1,
"1.1.1.1": 3
}
]
where each key would be every _id, and it's value their associated count. Is this possible to achieve?
I've tried so far adding at the end of the aggregate pipe a $project document like this one:
{
"$project": {
"_id": 0,
"$_id": "$count"
}
}
but it seems this doesn't work. Is there a way to achieve my desired query result or should I just stick to what I did so far and forget about it because it is not possible to achieve so?
The aggregation framework cannot output a key name from a value. The best place to do this in our application layer. As suggested in the comment, you could use either use the map reduce framework or forEach to achieve this, however, their performance is generally poorer, in particular in sharded environments, see the documentation.