Search array for dates within a range - mongodb

I am new to MongoDB, keep that in mind as I ask my questions please. I have the following collection named 'documents' where I have an array named attributes which contains key:value pairs of different types.
{
"_id" : ObjectId("5d376c67f6c305c7571f7dd7"),
"name" : "testContract.pdf",
"fileType" : "pdf",
"attributes" : [
{
"abc" : 1
},
{
"def" : ISODate("2012-12-01T08:00:00Z")
},
{
"ghi" : "test"
}
]
}
{
"_id" : ObjectId("5d376ca4f6c305c7571f7dd8"),
"name" : "1099.pdf",
"fileType" : "pdf",
"attributes" : [
{
"def" : ISODate("2012-06-03T07:00:00Z")
},
{
"ghi" : "taxes"
}
]
}
What I would like to do is return one or more documents from this collection that fit within a date range. For example I can return all documents that have a fileType of 'pdf' with the following query -->
db.documents.find({"fileType":"pdf"});
But what I am trying to figure out is can I search an array containing different data types like dates in a range successfully while also being able to search for strings. I can also search the attributes array with the following -->
db.documents.find({"attributes":{"ghi":"test"}});
Here is an example of what I am trying to get but it is not working...
db.documents.find({'attributes':$match:{[{'def':{$gte:new Date('2011-11-30')}}]}});

Is something like this what you are looking for?
Based on the following documents:
{
"_id" : ObjectId("5d38aad64850fbd5d13f14bd"),
"name" : "testxx.pdf",
"attributes" : [
{
"abc" : 1
},
{
"def" : ISODate("2012-12-01T08:00:00Z")
},
{
"ghi" : "test"
}
]
}
{
"_id" : ObjectId("5d38b0eae4adbe945b6cbb89"),
"name" : "testyy.pdf",
"attributes" : [
{
"abc" : 2
},
{
"def" : ISODate("2013-12-01T08:00:00Z")
},
{
"ghi" : "test1"
}
]
}
{
"_id" : ObjectId("5d38b12f21e647b8d384d841"),
"name" : "testzz.pdf",
"attributes" : [
{
"abc" : 3
},
{
"def" : ISODate("2012-05-01T08:00:00Z")
},
{
"ghi" : "test"
}
]
}
Query def > 2010/11/30 - returns all 3 docs above
db.chkdates.find({'attributes.def':{$gte:new Date(2010,11,30)}}).pretty()
Adding another key/value pair and range looks like:
db.chkdates.find({'attributes.def':{$gte:new Date(2011,12,12),
$lte:new Date(2012,10,12)},
'attributes.ghi':'test'}).pretty()
Returns only 1 document:
{
"_id" : ObjectId("5d38b12f21e647b8d384d841"),
"name" : "testzz.pdf",
"attributes" : [
{
"abc" : 3
},
{
"def" : ISODate("2012-05-01T08:00:00Z")
},
{
"ghi" : "test"
}
]
}

You can use the $gte and $lte for querying within a date range. It would look something like this:
{'def': { $gte: qryDateFrom, $lte: qryDateTo }}
Depending on if you're using aggregate pipleline or a regular mongoose query, you'd just apply this accordingly.
For instance, using $match in an aggregate with a string match included, it would look like this:
$match: {
$and: [
{'id': { $ne: req.user._id }},
{'def': { $gte: qryDateFrom, $lte: qryDateTo }}
]
}

Related

Mongodb query match with if condition form multiple fields with null values

I have a json where i am trying to filter my pipeline with multiple fields where some fields can have null value as well. sender.client and receiver.client may not always values
Below is the part of sample json:
{"sender" : {
"id" : "5d95",
"name" : "Name1",
"phone" : "123456",
"client" : "spec1"
},
"receiver" : {
"id" : "5d95683",
"name" : "name2",
"phone" : "342235",
"client" : "spec1"
}
}
{"sender" : {
"id" : "52fes",
"name" : "Name2",
"phone" : "3334321",
"client" : "spec2"
},
"receiver" : {
"id" : "5efse",
"name" : "name3",
"phone" : "7353344",
"client" : "spec1"
}
}
I am aiming to filter with condition if (sender.client = spec1 or receiver.client =spec1) then display all fields, i.e if the name of the client matches then i have to display other required fields. I have been trying with $project and $match but match is not working with $cond , so i have taken alternate route with $eq but it's not helping me filter out my requirement. Below is my code:
{
"$project" : {
"sendername" : {
"$cond" : {
"if" : {
"$eq" : [
"$sender.client",
"spec1"
]
},
"then" : "$sender.name",
"else" : 0.0
}
},
"sendername1" : {
"$cond" : {
"if" : {
"$eq" : [
"$receiver.client",
"spec1"
]
},
"then" : "$receiver.name",
"else" : 0.0
}
}
}
}
I want to use $match inpace of $eq. How do i accomplish this?
The $match with $exprcan filter based on the condition: (sender.client = spec1 or receiver.client = spec1)
I am aiming to filter with condition if (sender.client = spec1 or
receiver.client = spec1) then display all fields, i.e if the name of
the client matches then i have to display other required fields.
You can add further filter to match the name field (there are two fields with "name", sender.name and receiver.name; which one to match upon is not clear. I am assuming it can be any one).
var queryFilter = { $cond: {
if: { $or: [
{ $eq: [ "$sender.client", "spec1" ] },
{ $eq: [ "$receiver.client", "spec1" ] }
]
},
then: true,
else: false
}
};
db.test.aggregate( [
{
$match: {
$expr: { $eq: [ queryFilter, true ],
$or: [ { "sender.name" : "name3" }, { "receiver.name" : "name3" } ] }
}
}
] )
The match filter is: $expr: {...} and $or: [...].
Further, you can add other stages (e.g., $project) after the $match stage, as needed.

Reference multiple fields with aggregation function

Let's say I have some mongo DB query which returns following two documents. (I am using aggregation & projection which returns me this result set).
{
"name" : {
"value" : "ANDERSON"
},
"ID" : {
"value" : "2356"
},
}
{
"employeename" : {
"value" : "DAVID"
},
"ID" : {
"value" : "2356"
},
}
My DB is schema less & I am storing attributes and there values. There are multiple attributes which represents the same information. For e.g. here "name" & "employeename" represents the same thing. I want the final output in some common attribute (say "Employee Name"). This common attribute can have value either from "name" or "employeename".
I think this problem can be solved by adding one more pipe in with the aggregation. I tried $or (it returns true/false not the value)
db.getCollection('mycollection').aggregate([
{ "$project" : {
"name" : 1,
"ID" : 1, "employeename" : 1
}},
{ "$project":{
"Employee Name": {$or : ["$name", "$employeename"]}
}}
])
Final Output should be
{
" Employee Name" : {
"value" : "ANDERSON"
},
"ID" : {
"value" : "2356"
},
}
{
" Employee Name" : {
"value" : "DAVID"
},
"ID" : {
"value" : "2356"
},
}
Can somebody tell me how to write this mongo DB command?
What you want is the $ifNull operator, you can also shorten your pipeline to one $project stage.
db.getCollection('mycollection').aggregate([
{ "$project" : {
"EmployeeName" : { "$ifNull": [ "$name", "$employeename" ] },
"ID" : 1,
}}
])

Matched elements from mongodb records

Suppose I have following documents in my collection
{
"_id":ObjectId("562e7c594c12942f08fe4192"),
"tags" : [
{
"tagName" : "fun",
"created" : ISODate("2016-01-22T06:13:56.510Z")
},
{
"tagName" : "cool",
"created" : ISODate("2016-01-22T06:13:56.509Z")
},
{
"tagName" : "good",
"created" : ISODate("2016-01-22T06:13:56.509Z")
}
]
},
{
"_id":ObjectId("562e7c594c12942f08fe4193"),
"tags" : [
{
"tagName" : "super",
"created" : ISODate("2016-01-22T06:13:56.509Z")
},
{
"tagName" : "fun",
"created" : ISODate("2016-01-22T06:13:56.509Z")
}
]
}
I want to search relative tags and want to display tag array only.
How can I query to get the list of tag names?
To only query a specific field in MongoDB you can use the find method with the projection parameter:
https://docs.mongodb.org/manual/reference/method/db.collection.find/
db.test.find({}, {"tags.tagName":1,"_id":0}).pretty()
{
"tags" : [
{
"tagName" : "fun"
},
{
"tagName" : "cool"
},
{
"tagName" : "good"
}
]
}
The first parameter is blank {} because you don't have any query and the second parameter is your projection. With an embedded document you have to use the dot notation "tags.tagName". The "_id":0 to not display the _id field.

And not working in mongodb

i have a collection named student like
{
"_id" : ObjectId("5693b549c4fd0e0bf4782d73"),
"nameIdentity" : [
{
"name" : "a"
},
{
"name" : "b"
}
]
},
{
"_id" : ObjectId("5693b549c4fd0e0bf4782d74"),
"nameIdentity" : [
{
"name" : "a"
}
]
},
{
"_id" : ObjectId("5693b549c4fd0e0bf4782d75"),
"nameIdentity" : [
{
"name" : "a"
},
{
"name" : "b"
}
]
},
{
"_id" : ObjectId("5693b549c4fd0e0bf4782d76"),
"nameIdentity" : [
{
"name" : "b"
}
]
}
i am trying to query using 'and' but its giving me some different output.
When i query for all the nameIdentities which has only name "a" db.student.find({"nameIdentity.name":"a"}) i am expecting the output as 1 where as i am getting 3. Again when i query for names with both a and b db.student.find({"nameIdentity.name":"a"},{"nameIdentity.sourceReferenceId.sourceName":"b"}) i am expecting output as 2 but i am getting 4. Can any one suggest me where am i going wrong?
use this.
db.student.find({"nameIdentity.name":"a","nameIdentity": { $size: 1 }})
in your query
db.student.find({"nameIdentity.name":"a"}) you are searching for data which nameIdentity is "a" not only a. and in your second query use like
db.student.find({"nameIdentity.name":"a","nameIdentity.name":"b"})

Mongo: how to retrieve ONLY subdocs that match certain properties

Having, for example, a collection named test and the following document is inside:
{
"_id" : ObjectId("5692ac4562c824cc5167379f"),
"list" : [
{
"name" : "elem1",
"type" : 1
},
{
"name" : "elem2",
"type" : 2
},
{
"name" : "elem3",
"type" : 1
},
{
"name" : "elem4",
"type" : 3
},
{
"name" : "elem4",
"type" : 2
}
]
}
Let's say I would like to retrieve a list of only those subdocuments inside list that match:
type = 2.
I've tried the following query:
db.getCollection('test').find({
'_id': ObjectId("5692ac4562c824cc5167379f"),
'list.type': 1
})
But the result I get contains every subdocument inside list, and I guess this is because inside list there are at least one document which's type equals 1.
Instead of that, the result I am interested to obtain would be every subdocument inside list that matches 'list.type': 1:
{
"_id" : ObjectId("5692ac4562c824cc5167379f"),
"list" : [
{
"name" : "elem1",
"type" : 1
},
{
"name" : "elem3",
"type" : 1
}
]
}
...so $and $elemMatch is not what I am really looking for as they return just the first matching element.
Anyone knows how to achieve what I am looking for?
db.myCol.aggregate([
{ $unwind: "$list" },
{ $match: { "list.type":1 } },
{ $group: { "_id":"$_id", list: {$push:"$list"}} }
])