How to filter from array in a mongo document - arrays

I have a collection in mongoDB with documents like:
{
"_id" : ObjectId("some_id"),
"name" : "name",
"field1" : 123,
"field2" : 234,
"arr" : [
{
"a_num" : 3,
"arr" : [
"abc",
"def"
],
},
{
"a_num" : 36,
"arr" : [
"hi"
],
},
{
"a_num" : 34,
"arr" : [
"abc"
],
}
]
}
While I'm using find()
I don't want to get the arr elements where arr has only 1 element, that its value is "abc".
E.g, for the above document, I'd like to get:
{
"_id" : ObjectId("some_id"),
"name" : "name",
"field1" : 123,
"field2" : 234,
"arr" : [
{
"a_num" : 3,
"arr" : [
"abc",
"def"
],
},
{
"a_num" : 36,
"arr" : [
"hi"
],
},
]
}
Any idea how?
Thanks!

You'll need to use the aggregation framework with $filter, like so:
db.collection.aggregate([
{
$addFields: {
arr: {
$filter: {
input: "$arr",
cond: {
$ne: [
"$$this.arr",
[
"abc"
]
]
}
}
}
}
}
])

Related

Return Documents with Same Subarray elements

I have the following collection:
{ "_id" : 1, "tags" : [ "school", "home" ] }
{ "_id" : 2, "tags" : [ "school", "storage", "home" ] }
{ "_id" : 3, "tags" : [ "school", "storage", "home", "bones" ] }
{ "_id" : 4, "tags" : [ "school", "storage", "home", "bones", "milk" ] }
{ "_id" : 5, "tags" : [ "homes", "maps", "bones" ] }
{ "_id" : 6, "tags" : [ "xxx", "yyy", "zzz" ] }
I would like to return all documents where "tags" matches documents with exactly the same array elements.
So thus, if I were to query for tags == ["school", "home"] or tags == ["home", "school"], document w/ _id=1 would be returned
I am doing the following:
db.test.find({tags: {$in: ['school', 'home']}}) or
db.test.find({tags: {$in: ['home', 'school']}})
and the following are returned:
{ "_id" : 1, "tags" : [ "school", "home" ] }
{ "_id" : 2, "tags" : [ "school", "storage", "home" ] }
{ "_id" : 3, "tags" : [ "school", "storage", "home", "bones" ] }
{ "_id" : 4, "tags" : [ "school", "storage", "home", "bones", "milk" ] }
How may I achieve only item w/ _id=1 be returned?
Maybe something like this:
Option 1:
db.collection.find({
$and: [
{
tags: "school"
},
{
tags: "home"
},
{
tags: {
$size: 2
}
}
]
})
Explained:
Match if school & home are in the tags array and if array size is 2.
Playground
Option 2:
db.collection.find({
$or: [
{
tags: [
"school",
"home"
]
},
{
tags: [
"home",
"school"
]
}
]
})
Explained:
Match the two possible array options
Playground2

How to query Array in MongoDB?

i am new to MongoDB and I have documents as below
{ "_id" : ObjectId("604b7d62b19a72a2b89028e6"), "name" : "ram", "tags" : [ "mobile", "iphone", "india" ] }
{"_id" : ObjectId("604b7d83b19a72a2b89028e7"), "name" : "shyam", "tags" : [ "mobile", "iphone", "india" ] }
{ "_id" : ObjectId("604b7d9bb19a72a2b89028e8"), "name" : "ravi", "tags" : [ "mobile", "android", "india" ] }
{ "_id" : ObjectId("604b7db5b19a72a2b89028e9"), "name" : "aman", "tags" : [ "mobile", "android", "india" ] }
{ "_id" : ObjectId("604b7db5b19a72a2b89028e9"), "name" : "aman", "tags" : [ "windows", "usa" ] }
{ "_id" : ObjectId("604b7db5b19a72a2b89028e9"), "name" : "aman", "tags" : [ "tech", "apple", "microsoft" ] }
How to write query so that if i query for following tags ["mobile", "android", "12", "pro"] i would get following result
{ "_id" : ObjectId("604b7d9bb19a72a2b89028e8"), "name" : "ravi", "tags" : [ "mobile", "android", "india" ] }
{ "_id" : ObjectId("604b7db5b19a72a2b89028e9"), "name" : "aman", "tags" : [ "mobile", "android", "india" ] }
{ "_id" : ObjectId("604b7d62b19a72a2b89028e6"), "name" : "ram", "tags" : [ "mobile", "iphone", "india" ] }
{ "_id" : ObjectId("604b7d83b19a72a2b89028e7"), "name" : "shyam", "tags" : [ "mobile", "iphone", "india" ] }
Demo - https://mongoplayground.net/p/EMW8xgV1yrU
Use $in
The $in operator selects the documents where the value of a field equals any value in the specified array. To specify an $in expression, use the following prototype:
db.collection.find({
tags: { $in: [ "mobile", "android", "12", "pro" ] }
})

Checking $gt on a structure element in MongoDB [duplicate]

This question already has answers here:
How to query nested objects?
(3 answers)
Closed 2 years ago.
> db.inventory.find()
{ "_id" : ObjectId("5eb67598bee5213484d45087"), "item" : "journal", "qty" : 25, "status" : "A", "size" : { "h" : 14, "w" : 21, "uom" : "cm" }, "tags" : [ "blank", "red" ] }
{ "_id" : ObjectId("5eb67598bee5213484d45088"), "item" : "notebook", "qty" : 50, "status" : "A", "size" : { "h" : 8.5, "w" : 11, "uom" : "in" }, "tags" : [ "red", "blank" ] }
{ "_id" : ObjectId("5eb67598bee5213484d45089"), "item" : "paper", "qty" : 10, "status" : "D", "size" : { "h" : 8.5, "w" : 11, "uom" : "in" }, "tags" : [ "red", "blank", "plain" ] }
{ "_id" : ObjectId("5eb67598bee5213484d4508a"), "item" : "planner", "qty" : 0, "status" : "D", "size" : { "h" : 22.85, "w" : 30, "uom" : "cm" }, "tags" : [ "blank", "red" ] }
{ "_id" : ObjectId("5eb67598bee5213484d4508b"), "item" : "postcard", "qty" : 45, "status" : "A", "size" : { "h" : 10, "w" : 15.25, "uom" : "cm" }, "tags" : [ "blue" ] }
{ "_id" : ObjectId("5ebfd02b3a3b38a52be04608"), "item" : "journal", "qty" : 25, "tags" : [ "blank", "red" ], "dim_cm" : [ 14, 21 ] }
{ "_id" : ObjectId("5ebfd02b3a3b38a52be04609"), "item" : "notebook", "qty" : 50, "tags" : [ "red", "blank" ], "dim_cm" : [ 14, 21 ] }
{ "_id" : ObjectId("5ebfd02b3a3b38a52be0460a"), "item" : "paper", "qty" : 100, "tags" : [ "red", "blank", "plain" ], "dim_cm" : [ 14, 21 ] }
{ "_id" : ObjectId("5ebfd02b3a3b38a52be0460b"), "item" : "planner", "qty" : 75, "tags" : [ "blank", "red" ], "dim_cm" : [ 22.85, 30 ] }
{ "_id" : ObjectId("5ebfd02b3a3b38a52be0460c"), "item" : "postcard", "qty" : 45, "tags" : [ "blue" ], "dim_cm" : [ 10, 15.25 ] }
Both of the following queries are resulting in nothing:
> db.inventory.find( { size: { h: { $gt: 14 } } } )
>
> db.inventory.find( { size: { $elemMatch: { h: { $gt: 14 } } } } )
Whereas there is a document greater than 14:
{ "_id" : ObjectId("5eb67598bee5213484d4508a"), "item" : "planner", "qty" : 0, "status" : "D", "size" : { "h" : 22.85, "w" : 30, "uom" : "cm" }, "tags" : [ "blank", "red" ] }
Following syntax doesn't work:
> db.inventory.find( { size.h: { $gt: 14 } } )
2020-05-24T15:08:44.306+0530 E QUERY [js] uncaught exception: SyntaxError: missing : after property id :#(shell):1:25
`
Please explain why.
You need to add dot notation while querying nested documents. Can you try this
db.inventory.find( { 'size.h': { $gt: 14 } } )

mongodb node.js nested array fields concatenation single variable result

I am using using this code inside model aggregation
{$project:{
//for brevity
}},
{$project:{
"employe_detail":{
"$map":{
"input":"$employe_detail",
"as":"names",
"in":{
"name":{"$concat":["$$names.first_name",
" ","$$names.other_names"," ",
"$$names.last_name"]}
}
}
}
}}
This is the result
{ "employe_detail" : [ { "name" : "Brian Smith" } ] }
{ "employe_detail" : [ { "name" : "Josh Clefton" } ] }
{ "employe_detail" : [ { "name" : "Treasure Dwayne" } ] }
when I try to extend the result fields output
{$project:{
//for brevity
}},
{$project:{
"employe_detail":{
"$map":{
"input":"$employe_detail",
"as":"names",
"in":{
"name":{"$concat":["$$names.first_name",
" ","$$names.other_names"," ",
"$$names.last_name"]},
"dept":"$$names.activity_year.activity_detail.dept",
"time_spent": "$$names.activity_year.activity_detail.activity_time_spent.time_spent",
"shift": "$$names.activity_year.activity_detail.activity_time_spent.shift"
}
}
}
}}
The result was
{ "employe_detail" : [ { "name" : "Brian Smith", "dept" : [ [ "spray", "smoothing", "assembling", "packaging" ] ],"time_spent" : [ [ [ 6 ], [ 15 ], [ 7 ], [ 8 ]] ], "shift" : [ [ [ "afternoon" ], [ "afternoon" ], [ "morning" ], [ "morning" ] ] ]} ] }
{ "employe_detail" : [ { "name" : "Josh Clefton", "dept" : [ [ "spray", "shining", "shaping", "smoothing"] ],"time_spent" : [ [ [ 5 ], [ ], [ 8 ], [ 10 ] ] ], "shift" : [ [ [ "afternoon" ], [ ], [ "night" ], [ "night" ] ] ] } ] }
{ "employe_detail" : [ { "name" : "Treasure Dwayne", "dept" : [ [ "spray", "shaping", "smoothing", "assembling" ] ], "time_spent" : [ [ [ 3 ], [ 9 ], [ 13 ], [ 9 ] ] ], "shift" : [ [ [ "morning" ], [ "morning" ], [ "morning" ], [ "morning" ] ] ] } ] }
Please how can I (at least) get something similar to this
{ "employe_detail" : [ { "name" : "Brian Smith",
{"dept" : "spray", "time_spent":6, "shift": "afternoon"},
{"dept" : "smoothing", "time_spent": 15 , "shift": "afternoon"},
{"dept" : "assembling", "time_spent": 7, "shift": "morning"},
{"dept" : "packaging", "time_spent": 8, "shift": "morning"}
}]}
{ "employe_detail" : [ { "name" : "Josh Clefton",
{"dept" : "spray", "time_spent":5, "shift": "afternoon"},
{"dept" : "shining", "time_spent": , "shift": },
{"dept" : "shaping", "time_spent": 8, "shift": "night"},
{"dept" : "smoothing", "time_spent": 10, "shift": "night"}
}]}
Preferably I would like to get a data to become a variable name i.e. for example
instead of time_spent as the variable name, it should be the data for dept that would be the variable name
{ "employe_detail" : [ { "name" : "Josh Clefton",
{"spray":5, "shift": "afternoon"},
{"shining": , "shift": },
{"shaping": 8, "shift": "night"},
{"smoothing": 10, "shift": "night"}
}]}
Please how can i achieve the above
UPDATE
This is sample data
{ "_id" : ObjectId("5bd548380a84d90b5c2bb416"), "details" : {"first_name" : "Brian", "other_names" : "Stone", "last_name" : "Smith", "gender" : "male", "date_of_birth" : ISODate("2009-03-05T00:00:00Z") }, "contact" : [ { "_id" : ObjectId("5bd548380a84d90b5c2bb417"), "residential_address" : "no 5 smith"} ], "health" : [ { "_id" : ObjectId("5bd548380a84d90b5c2bb419"), "illness_name" : "Cold", "sypmtom" : "Sneezing", "normal_treatment" : ""} ], "activity_year" : { "_id" : ObjectId("5bd548380a84d90b5c2bb41a"), "activity_detail" : [ { "_id" : ObjectId("5bd548380a84d90b5c2bb41b"), "dept" : "spray", "activity_time_spent" : [ ] }, { "_id" : ObjectId("5bd548390a84d90b5c2bb41c"), "dept" : "smoothing", "activity_time_spent" : [ ] }, { "_id" : ObjectId("5bd548390a84d90b5c2bb41e"), "dept" : "assembling", "activity_time_spent" : [ ] }, { "_id" : ObjectId("5bd548390a84d90b5c2bb420"), "dept" : "packaging", "activity_time_spent" : [ ] }, { "_id" : ObjectId("5bd54add0a84d90b5c2bb5c5"), "dept" : "shining", "activity_time_spent" : [ ] }, { "_id" : ObjectId("5bff847078c700209c1b515f"), "dept" : "shining", "activity_time_spent" : [ { "_id" : ObjectId("5c1d659083e7551854c1681d"), "time_spent" : 10, "shift" : "afternoon", }, { "_id" : ObjectId("5c1d659083e7551854c1681e"), "time_spent" : 10, "shift" : "afternoon"} ] } ]}, "__v" : 14 },
{ "_id" : ObjectId("5bd548bf0a84d90b5c2bb45b"), "details" : {"first_name" : "Treasure", "other_names" : "Bliss", "last_name" : "Dwayne", "gender" : "female", "date_of_birth" : ISODate("2010-10-28T00:00:00Z") }, "contact" : [ { "_id" : ObjectId("5bd548bf0a84d90b5c2bb45c"), "residential_address" : "no 5 smith"} ], "health" : [ {"_id" : ObjectId("5bd548bf0a84d90b5c2bb45e"), "illness_name" : "Cold", "sypmtom" : "Sneezing", "normal_treatment" : ""} ], "activity_year" : { "_id" : ObjectId("5bd548bf0a84d90b5c2bb45f"), "activity_detail" : [ { "dept" : "spray", "activity_time_spent" : [ ] }, { "dept" : "smoothing", "activity_time_spent" : [ { "_id" : ObjectId("5c200ccea72a3e11f895dc26"), "time_spent" : 3, "shift" : "morning"}, { "_id" : ObjectId("5c215d2eea2ebe1c8043ccde"), "time_spent" : 5, "shift" : "morning"} ] }, { "dept" : "packaging", "activity_time_spent" : [ { "_id" : ObjectId("5c203e75084852185c583e13"), "time_spent" : 9,"shift" : "afternoon"}, { "_id" : ObjectId("5c20f50f4feffe0b00e8e9f7"), "time_spent" : 18,"shift" : "afternoon"} ] }, { "dept" : "shining", "activity_time_spent" : [ { "_id" : ObjectId("5c200b38a72a3e11f895dc08"), "time_spent" : 9, "shift" : "night", }, { "_id" : ObjectId("5c215acdea2ebe1c8043ccc0"), "time_spent" : 9, "shift" : "night" } ] }] }, "__v" : 9 },
None of your expected outputs is a valid JSON document but I hope that below solution will guide you to something that suits your needs.
First of all to create document keys dynamically you have to use $arrayToObject operator which expects an array of two-element arrays as an input. So you can use $addFields operator to reshape your activity_year.activity_detail array into that kind of format. You can use $map to do that and I assume you need first time_spent ($arrayElemAt used to get first element). Then you can use $concatArrays in the next stage to combine that data with name , try:
db.col.aggregate([
{
$addFields: {
activities: {
$map: {
input: "$activity_year.activity_detail",
as: "activity",
in: {
$let: {
vars: {
first_time_spent: { $arrayElemAt: [ "$$activity.activity_time_spent", 0 ] }
},
in: [
[ "$$activity.dept", { $ifNull: [ "$$first_time_spent.time_spent", "" ] } ],
[ "shift", { $ifNull: [ "$$first_time_spent.shift", "" ] } ]
]
}
}
}
}
}
},
{
$project: {
employee_details: {
$concatArrays: [
[{ "name": { $concat: [ "$details.first_name", " ","$details.other_names", " ", "$details.last_name"] } }],
{
$map: {
input: "$activities",
as: "a",
in: { $arrayToObject: "$$a" }
}
}
]
}
}
}
])
Outputs the data in following format:
{
"_id" : ObjectId("5bd548bf0a84d90b5c2bb45b"),
"employee_details" : [
{
"name" : "Treasure Bliss Dwayne"
},
{
"spray" : "",
"shift" : ""
},
{
"smoothing" : 3,
"shift" : "morning"
},
{
"packaging" : 9,
"shift" : "afternoon"
},
{
"shining" : 9,
"shift" : "night"
}
]
}

MongoDB - find any document with array combinations

mongo documents are like:
{
_id: '',
names: ['ab', 'bc']
}
{
_id: '',
names: ['ab', 'de', 'fg']
}
{
_id: '',
names: ['bc']
}
{
_id: '',
names: ['ab', 'bc', 'cd']
}
I have an input array:
['ab', 'bc', 'cd']
Question : How to get all the documents, where 'names' is equal to any combination of the input array ?
Result : all documents where 'names' is any of below should return
['ab']
['bc']
['cd']
['ab', 'bc']
['bc', 'ab']
['bc', 'cd']
['cd', 'bc']
... and so on..
['ab', 'bc', 'cd']
You can use $expr in find to get the $size of $setIntersection with names array
db.tt.find({$expr : {$gt : [{$size : {$setIntersection : ["$names", ["ab","bc","cd"]]}}, 0]}})
sample collection
> db.tt.find()
{ "_id" : "1", "names" : [ "ab", "bc" ] }
{ "_id" : "2", "names" : [ "ab", "de", "fg" ] }
{ "_id" : "3", "names" : [ "bc" ] }
{ "_id" : "4", "names" : [ "ab", "bc", "cd" ] }
with $expr and $setIntersection
> db.tt.find({$expr : {$gt : [{$size : {$setIntersection : ["$names", ["ab","bc","cd"]]}}, 0]}})
{ "_id" : "1", "names" : [ "ab", "bc" ] }
{ "_id" : "2", "names" : [ "ab", "de", "fg" ] }
{ "_id" : "3", "names" : [ "bc" ] }
{ "_id" : "4", "names" : [ "ab", "bc", "cd" ] }
with $in (as given in comments by Anthony)
> db.tt.find({names : {$in : ["ab","bc","cd"]}})
{ "_id" : "1", "names" : [ "ab", "bc" ] }
{ "_id" : "2", "names" : [ "ab", "de", "fg" ] }
{ "_id" : "3", "names" : [ "bc" ] }
{ "_id" : "4", "names" : [ "ab", "bc", "cd" ] }

Resources