I need to find a document either when a field doesn't exist or when a subfield of this field meets some condition.
A similar question was asked here: Mongodb query - apply condition only if field exists. I'll use the code from this answer to illustrate:
db.stackoverflow.find({
$or: [
{ howmuch: { $exists:false } },
{ 'howmuch.chocolate':5 }
]})
Of course when I do that I get an error when howmuch is undefined. I know I could test if 'howmuch.chocolate' exists but that wouldn't change anything. Is there a way to do that?
This should work:
db.stackoverflow.find({
$or: [
{ howmuch: { $exists:false } },
{ $and: [{ 'howmuch.chocolate': { $exists: true } } ,{ 'howmuch.chocolate':5 }]}
]})
According to the documentation, if the first expression in the $and array evaluates to false, the remaining expressions are not evaluated.
Related
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.
I want to find whether embedded document exists in array property of parent document and get the parent document's a property value.
Think, I have a document like this
{
_id:1,
persons:[{name: "Jack", earning: 1000},{name: "Monica", earning: 2000}]
totalDebt:500
}
I want to find whether name=Jamal exists in person array's embedded document and with this the totalDebt of _id=1
The result will be like this:
{
totalDebt:500,
exists:false // as Jamal does not exists
}
How execute this in a single query ?
Yes, you can easily solve this by using one query. I solved this by one query using $cond, Look below code to get a brief understanding.
db.getCollection('collectionName').aggregate([
{
$project: {
_id: 0,
totalDebt: 1,
"exists": {
$cond: {
if: {
$in: [
"Jack",
"$persons.name"
]
},
then: true,
else: false
}
}
}
}
])
Initially, I have used $cond with $eq operator, it always returns false. When I use $in, it solved my problem.
Hi I'm new with mongodb and I have to write a query to check if each field in database has a parent, if yes change the hasChild field to "true" else leave it be the default value of false.
Here is sample of one Document.
{
"_id":"5e19ef611052250ba51abb7b",
"name":"shampoo",
"price":12.99,
"hasChild":true
}
{
"_id":"5e1b268d25fe046b3518dcb9",
"name":"conditioner",
"price":"13.99",
"parent":"5e19ef611052250ba51abb7b",
"hasChild":false
}
I though a query which could ,while updating a filed search in other documents, check whether they have a parent id same as current documents id and set true/false would work out. but I couldn't find a way to write it. I would appreciate any ideas.
note that "_id" and "parent" are ObjectId.
You can do it with aggregation framework.
Something like this with $addFields and $cond:
db.getCollection("yourcollection").aggregate(
[
{
$addFields: {
"hasChild": {
$cond: { if: { $eq: [ "$parent", undefined ] }, then: false, else: true }
}
}
},
]
);
I'm performing an aggregation on a MongoDB collection. The steps preceeding the topical $cond are not important, so I'll redact them for brevity:
db.mycoll.aggregate([
{ $match: ... },
{ $project: ... },
{ /* this is the problem step */ }
])
The documents that are being generated by step 2, $project, are shaped like this:
{
"blueTeam": true,
"redTeam": false,
"winner": true
}
Now assuming I add an additional projection which utilizes $cond - I'm not permitted to address the fields from the projected document. Here's a naive example:
{
$project: {
blueTeam: "$blueTeam",
winnerAsInteger: {
$cond: [ { "$winner": true }, 1, 0 ]
}
}
}
Expectation: The pipeline emits documents in which winning documents have field winnerAsInteger equal to 1, otherwise 0.
Reality: This pipeline step produces an error.
In Node's MongoDB client, the error is as follows:
(node:34380) UnhandledPromiseRejectionWarning: MongoError: Unrecognized expression '$winner'
In MongoDB Compass's aggregation GUI, the error is:
Field must not begin with '$' or '.', field path was: $winner
This seems to directly contradict the documentation regarding this, which references document fields with the $ syntax.
I'm on MongoDB 4.0.5, for what it's worth.
Try
{$eq:[ "$winner", true ]} instead of { "$winner": true }
Courtesy of #s7vr in comments, just added it here so that people don't think it's an unanswered question!
Implementing an application that looks up a table for mail id presence from a list of around 10 email ids. Tried using $or and $in.
$in seems to give better performance but not significant. Is one more optimized than other?
MongoDB docs have the answer:
"When using $or with <expressions> that are equality checks for the value of the same field, choose the $in operator over the $or operator."
$or operator is logical operator where you can define your own login but $in operator is Comparison operator where you can compare you can not put your on logic.
Syntax of $in:
{ field: { $in: [<value1>, <value2>, ... <valueN> ] } }
Example:
db.account.find( { qty: { $in: [ 5, 15 ] } } )
Syntax of $or:
{ $or: [ { <expression1> }, { <expression2> }, ... , { <expressionN> } ] }
Example:
db.account.find( { $or: [ { quantity: { $lt: 20 } }, { price: 10 } ] } )
Note: Account is your collection name
"While "$or"will always work, use "$in"whenever possible as the query optimizer
handles it more efficiently."
Moreover "$in" has more readability.
Ref: MongoDB: The Definitive Guide
Well that will insure no indecis to be ensured if you use $in, however i prefer to format it to $or as it will ensure index (readability won't concern me at is being handled in application logic in which i prefer to consume the memory of app rather than mongodb server)