How to create a nested And/Or Condition in mongoDB query? - mongodb

I have the below SQL query,
SELECT *
FROM [TestDB].[dbo].[EmpTbl] WHERE
(EmpDept='IT' and EmpDept='Account')
OR (EmpDept='HR' or EmpDept='Finance')
AND (EmpDept='Sales' or EmpDept='Admin')
How can I write the equivalent query for mongoDB?

As per your question I don't understand your document structure but as per your question I created following documents
{ "_id" : ObjectId("547bfbc78849d6c59671b8e3"), "EmpDept" : "IT" }
{ "_id" : ObjectId("547bfbce8849d6c59671b8e4"), "EmpDept" : "Account" }
{ "_id" : ObjectId("547bfbd48849d6c59671b8e5"), "EmpDept" : "HR" }
{ "_id" : ObjectId("547bfbdb8849d6c59671b8e6"), "EmpDept" : "Finance" }
{ "_id" : ObjectId("547bfbe38849d6c59671b8e7"), "EmpDept" : "Sales" }
{ "_id" : ObjectId("547bfbeb8849d6c59671b8e8"), "EmpDept" : "Admin" }
And query for obtaining result as below
db.collectionName.find({
"$and": [
{
"EmpDept": "IT",
"EmpDept": "Account"
},
{
"$or": [
{
"$or": [
{
"EmpDept": "HR",
"EmpDept": "Finance"
}
]
},
{
"$and": [
{
"EmpDept": "Sales",
"EmpDept": "Admin"
}
]
}
]
}
]
})

Related

How to search mongodb

I have two JSONs in a collection in mongodb and would like to write a bson.M filter to fetch the first JSON below.
I tried with the filter below to get the first JSON but got no result.
When the first JSON is in the collection, I get result when i use the filter
but when i have both JSONs, I do not get a result. Need help.
filter := bson.M{"type": "FPF", "status": "REGISTERED","fpfInfo.fpfInfoList.ssai.st": 1, "fpfInfo.fpfInfoList.infoList.dn": "sim"}
{
"_id" : "47f6ad68-d431-4b69-9899-f33d828f8f9c",
"type" : "FPF",
"status" : "REGISTERED",
"fpfInfo" : {
"fpfInfoList" : [
{
"ssai" : {
"st" : 1
},
"infoList" : [
{
"dn" : "sim"
}
]
}
]
}
},
{
"_id" : "347c8ed2-d9d1-4f1a-9672-7e8a232d2bf8",
"type" : "FPF",
"status" : "REGISTERED",
"fpfInfo" : {
"fpfInfoList" : [
{
"ssai" : {
"st" : 1,
"ds" : "000004"
},
"infoList" : [
{
"dn" : "sim"
}
]
}
]
}
}
db.collection.aggregate([
{
"$unwind": "$fpfInfo.fpfInfoList"
},
{
"$match": {
"fpfInfo.fpfInfoList.ssai.ds": {
"$exists": false
},
"fpfInfo.fpfInfoList.infoList.dn": "sim",
"fpfInfo.fpfInfoList.ssai.st": 1
}
}
])
Playground

MongoDB query using values priority

I have following documents in my collection:
/* 1 */
{
"_id" : ObjectId("5ea32d11f213c27c35395fd3"),
"name" : "Test",
"state" : "OH",
"code" : "CDM"
}
/* 2 */
{
"_id" : ObjectId("5ea32d29f213c27c35395fe0"),
"name" : "Test1",
"state" : "ALL",
"code" : "CDM"
}
/* 3 */
{
"_id" : ObjectId("5ea32d38f213c27c35395fe7"),
"name" : "Test2",
"state" : "OH",
"code" : "ALL"
}
/* 4 */
{
"_id" : ObjectId("5ea32d46f213c27c35395feb"),
"name" : "Test3",
"state" : "ALL",
"code" : "ALL"
}
Trying to filter documents based on state and code.
But there are few criteria if particular state or code is not found then search with value ALL
Example 1:
state = CA
code = CDM
then return only
{
"_id" : ObjectId("5ea32d29f213c27c35395fe0"),
"name" : "Test1",
"state" : "ALL",
"code" : "CDM"
}
Example 2:
state = CA
code = DCM
then return only
{
"_id" : ObjectId("5ea32d46f213c27c35395feb"),
"name" : "Test3",
"state" : "ALL",
"code" : "ALL"
}
etc..
The query that i tried was state = CA ,code = CDM:
db.getCollection('user_details').aggregate([
{'$match': { 'state': {'$in': ['CA','ALL']},
'code': {'$in': ['CDM','ALL']}}}
])
return was:
/* 1 */
{
"_id" : ObjectId("5ea32d29f213c27c35395fe0"),
"name" : "Test1",
"state" : "ALL",
"code" : "CDM"
}
/* 2 */
{
"_id" : ObjectId("5ea32d46f213c27c35395feb"),
"name" : "Test3",
"state" : "ALL",
"code" : "ALL"
}
Expected was :
{
"_id" : ObjectId("5ea32d29f213c27c35395fe0"),
"name" : "Test1",
"state" : "ALL",
"code" : "CDM"
}
Could you help to solve this issue.
Try below query :
db.collection.find({
$or: [
{
state: "CA",
code: "CDM"
},
{
state: "ALL",
code: "CDM"
},
{
state: "ALL",
code: "ALL"
},
{
state: "CA",
code: "ALL"
}
]
})
So basically you can not achieve what you're looking for in one query, you can try aggregation operator $facet & $switch to do this but I would not prefer to do that cause each stage in facet will do the given operation on entire collection's data. Instead get fewer docs using above query & in your code you can actually filter for best suited doc, Which would be easy & efficient. Don't forget to maintain indexes on DB.
Test : mongoplayground
Try this one:
db.user_details.aggregate([
{
$facet: {
match: [
{
"$match": {
$or: [
{
"state": "CA",
"code": {
"$in": [ "CDM", "ALL" ]
}
},
{
"state": {
"$in": [ "CA", "ALL"]
},
"code": "CDM"
}
]
}
}
],
all: [
{
"$match": {
"state": "ALL",
code: "ALL"
}
}
]
}
},
{
$project: {
match: {
$cond: [
{
$eq: [ { $size: "$match" }, 0]
},
"$all",
"$match"
]
}
}
},
{
$unwind: "$match"
},
{
$replaceWith: "$match"
}
])
MongoPlayground

MongoDB returne embedded documents of embedded documents without any parent documents? [duplicate]

This question already has answers here:
$replaceRoot in mongodb aggregation
(2 answers)
Closed 3 years ago.
I wrote the following code in MongoDB:
db.departments.insert({name:"Accounting",teams:[
{name:"Alpha team",employees:[
{name:"john"},
{name:"david"}
]},
{name:"True team",employees:[
{name:"oliver"},
{name:"sam"}
]}
]});
db.departments.insert({name:"Engineering",teams:[
{name:"Blue team",employees:[
{name:"singh"},
{name:"jane"}
]},
{name:"Lazy team",employees:[
{name:"marleen"},
{name:"florence"}
]}
]});
I want to do the equivalent of SELECT name FROM employee WHERE name LIKE '%o%' ORDER BY name DESC and get the results [{"name":"oliver"},{"name":"john"},{"name":"florence"}].
I just became aware of projections, so I tried this:
db.departments.find({"teams.employees.name":/.*o.*/}, {_id:0, "teams.employees.name": 1}).pretty();
But the result was this instead:
{
"teams" : [
{
"employees" : [
{
"name" : "john"
},
{
"name" : "david"
}
]
},
{
"employees" : [
{
"name" : "oliver"
},
{
"name" : "sam"
}
]
}
]
}
{
"teams" : [
{
"employees" : [
{
"name" : "singh"
},
{
"name" : "jane"
}
]
},
{
"employees" : [
{
"name" : "marleen"
},
{
"name" : "florence"
}
]
}
]
}
What is wrong with my syntax? I am open to other suggestions to achieve my objective
Use
db.departments.aggregate([
{ $unwind: "$teams" },
{ $unwind: "$teams.employees" },
{ $project: { _id: 0, name: "$teams.employees.name" } },
{ $match: { "name": { $regex: /.*o.*/ }} }
]).toArray()
Result
[
{
"name" : "john"
},
{
"name" : "oliver"
},
{
"name" : "florence"
}
]

How select under documents via $in operator in MongoDB?

I want grab all under documents via Id's like the following SQL query:
Select * from table
where subdoc1.id in (1234, 2345, 3456)
or subdoc2.id in (1234, 2345, 3456)
Here is the structure of my document:
{
"id" : new ObjectId("234565"),
"subdocs1" : [ {
"id" : "1234",
... },
{
"id": "2345",
... }],
"subdocs2" : [ {
"id" : "3456",
... },
{
"id": "7890",
... }]
}
How would the query look like in MongoDB?
db.collection.find({
$and : [{"subdocs1._id": {"$in" : ["1234", "2345", "3456"]},
{"subdocs2._id": {"$in" : ["1234", "2345", "3456"]}}]
})
OR
db.collection.find({
$and : [{"subdocs1":{"$elemMatch" : {"$_id" : {"$in" : ["1234", "2345", "3456"]}}}},
{"subdocs2:{"$elemMatch" : {"$_id" : {"$in" : ["1234", "2345", "3456"]}}}}]
})
Here my query, that works:
db.getCollection('documents').find({
$or : [
{ "subdoc1._id" : { "$in" : [ new ObjectId("5807a60afc84c80a5ea86218"), new ObjectId("5808ac5cfc841deda17f827b") ] } },
{ "subdoc2._id" : { "$in" : [ new ObjectId("5807a60afc84c80a5ea86218"), new ObjectId("5808ac5cfc841deda17f827b") ] } },
{ "subdoc3._id" : { "$in" : [ new ObjectId("5807a60afc84c80a5ea86218"), new ObjectId("5808ac5cfc841deda17f827b") ] } },
{ "subdoc4._id" : { "$in" : [ new ObjectId("5807a60afc84c80a5ea86218"), new ObjectId("5808ac5cfc841deda17f827b") ] } }
]})
Thanx!!

How to check if nested arrays are ALL empty in mongodb?

I have something like below:
{
"_id" : "1",
"firstArray" : [
{
"_id" : "11",
"secondArray" : [ ]
},
{
"_id" : "12",
"secondArray" : [ ]
},
{
"_id" : "13",
"secondArray" : [ { "type" : "somthing" } ]
}
]
},
{
"_id" : "2",
"firstArray" : [
{
"_id" : "21",
"secondArray" : [ ]
},
{
"_id" : "22",
"secondArray" : [ ]
}
]
}
I need a mongodb query to find documents which ALL of the nested secondArrays are empty? the query should return second document and not the first one.
to solve that, we need to check size of arr2, but to enable that we need first to unwind arr1.
Please find below aggregation framework snippet which solves this problem,
db.pmoubed.aggregate([{
$unwind : "$firstArray"
}, {
$project : {
_id : 1,
firstArray : 1,
isNotEmpty : {
$size : "$firstArray.secondArray"
}
}
}, {
$group : {
_id : "$_id",
isNotEmpty : {
$sum : "$isNotEmpty"
},
firstArray : {
$push : "$firstArray"
}
}
}, {
$match : {
"isNotEmpty" : 0
}
}
])
Any comments welcome