I have following Mongodb document. Would like to fetch document where participant = 'xxx' and message.lastmodifiedDate > dt and (message.touserid = 'xxx' or message.fromuserid = 'xxx').
{
"_id": {
"$oid": "575161ea02758f067057b8a8"
},
"_class": "com.idearealty.product.shopchat.persistence.model.Discussion",
"participants": "56d314a8e4b04d7f98cfd0c6,56d5d48ee4b0cc330f512a47,56d9d599e4b0cc330f512aaa,57130299e4b08c554c1092c7,56841002eceefce22f455c7f",
"messages": [
{
"_id": {
"$oid": "575161e802758f067057b8a4"
},
"formuserId": "56841002eceefce22f455c7f",
"fromuser": "9674642375",
"touserId": "56d314a8e4b04d7f98cfd0c6",
"touser": "debopam_r",
"message": "User Creating Discussion",
"isMute": false,
"index": 1,
"createDate": {
"$date": "2016-06-03T10:54:32.428Z"
},
"lastModifiedDate": {
"$date": "2016-06-03T10:54:32.428Z"
},
"createdBy": "9674642375",
"lastModifiedBy": "9674642375"
},
{
"_id": {
"$oid": "575161e902758f067057b8a5"
},
"formuserId": "56841002eceefce22f455c7f",
"fromuser": "9674642375",
"touserId": "56d5d48ee4b0cc330f512a47",
"touser": "Raushan",
"message": "User Creating Discussion",
"isMute": false,
"index": 2,
"createDate": {
"$date": "2016-06-03T10:54:33.006Z"
},
"lastModifiedDate": {
"$date": "2016-06-03T10:54:33.006Z"
},
"createdBy": "9674642375",
"lastModifiedBy": "9674642375"
},
{
"_id": {
"$oid": "575161e902758f067057b8a6"
},
"formuserId": "56841002eceefce22f455c7f",
"fromuser": "9674642375",
"touserId": "56d9d599e4b0cc330f512aaa",
"touser": "anirbanshop1",
"message": "User Creating Discussion",
"isMute": false,
"index": 3,
"createDate": {
"$date": "2016-06-03T10:54:33.572Z"
},
"lastModifiedDate": {
"$date": "2016-06-03T10:54:33.572Z"
},
"createdBy": "9674642375",
"lastModifiedBy": "9674642375"
},
{
"_id": {
"$oid": "575161ea02758f067057b8a7"
},
"formuserId": "56841002eceefce22f455c7f",
"fromuser": "9674642375",
"touserId": "57130299e4b08c554c1092c7",
"touser": "dummyshop",
"message": "User Creating Discussion",
"isMute": false,
"index": 4,
"createDate": {
"$date": "2016-06-03T10:54:34.208Z"
},
"lastModifiedDate": {
"$date": "2016-06-03T10:54:34.208Z"
},
"createdBy": "9674642375",
"lastModifiedBy": "9674642375"
}
],
"productId": "56841004eceefce22f455c9b",
"product": {
"_id": {
"$oid": "56841004eceefce22f455c9b"
},
"category": "Services",
"productName": "Driving School",
"imageurl": "service_icon.png",
"createDate": {
"$date": "2015-12-30T17:10:28.644Z"
},
"lastModifiedDate": {
"$date": "2015-12-30T17:10:28.644Z"
},
"createdBy": "UnAuntenticatedUser",
"lastModifiedBy": "UnAuntenticatedUser"
},
"userToRetailer": {
"57130299e4b08c554c1092c7": {
"_id": {
"$oid": "5713029ae4b08c554c1092c8"
},
"shopName": "dummyshop",
"user": {
"$ref": "IdeaRealtyUser",
"$id": {
"$oid": "57130299e4b08c554c1092c7"
}
}
},
"56d314a8e4b04d7f98cfd0c6": {
"_id": {
"$oid": "56d314a9e4b04d7f98cfd0c7"
},
"shopName": "Test Shop",
"user": {
"$ref": "IdeaRealtyUser",
"$id": {
"$oid": "56d314a8e4b04d7f98cfd0c6"
}
}
},
"56d9d599e4b0cc330f512aaa": {
"_id": {
"$oid": "56d9d59ae4b0cc330f512aab"
},
"shopName": "anirbanshop1",
"user": {
"$ref": "IdeaRealtyUser",
"$id": {
"$oid": "56d9d599e4b0cc330f512aaa"
}
}
},
"56d5d48ee4b0cc330f512a47": {
"_id": {
"$oid": "56d5d48fe4b0cc330f512a48"
},
"shopName": "Kolkata Shop1",
"user": {
"$ref": "IdeaRealtyUser",
"$id": {
"$oid": "56d5d48ee4b0cc330f512a47"
}
}
}
},
"messageCount": 4,
"createDate": {
"$date": "2016-06-03T10:54:34.215Z"
},
"lastModifiedDate": {
"$date": "2016-06-03T10:54:34.215Z"
},
"createdBy": "9674642375",
"lastModifiedBy": "9674642375"
}
I am using following java code to fetch the data, which translates to query
{ "aggregate" : "discussion" , "pipeline" : [ { "$match" : { "participants" : { "$regex" : "56d314a8e4b04d7f98cfd0c6"}}} , { "$unwind" : "$messages"} , { "$match" : { "$and" : [ { "messages.lastModifiedDate" : { "$gte" : { "$date" : "2016-02-28T16:06:11.960Z"}}} , { "$or" : [ { "messages.touserId" : "56d314a8e4b04d7f98cfd0c6"} , { "messages.formuserId" : "56d314a8e4b04d7f98cfd0c6"}]}]}} , { "$sort" : { "messages.lastModifiedDate" : -1}} , { "$skip" : 0} , { "$limit" : 10} , { "$group" : { "_id" : { "_id" : "$_id" , "productId" : "$productId"} , "data" : { "$push" : "$messages"}}} , { "$project" : { "productId" : "$_id.productId" , "data" : 1}}]}
But this query doesn't fecth any record. If I change the Date to ISODate it fetches expected result.
db.discussion.aggregate( [{ "$match" : { "participants" : { "$regex" : "56841002eceefce22f455c7f"}}} , { "$unwind" : "$messages"}, { "$match" : { "$and" : [ { "messages.lastModifiedDate" : { "$gte" : ISODate("2016-02-28T16:38:48.632Z")}} , { "$or" : [ { "messages.touserId" : "56841002eceefce22f455c7f"} , { "messages.formuserId" : "56841002eceefce22f455c7f"}]}]}}]);
Could you please let me know what changes is required so that it fetches using ISODate or while inserting the document it uses normal java.util.Date object? I tried with commented code as well but it didn't work.
public List<Discussion> findInbox(String userid,Date lastloginDate,int skip, int limit){
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
Aggregation aggr = newAggregation(
match(Criteria.where("participants").regex(Pattern.compile(userid))),
unwind("messages"),
match(new Criteria().andOperator(Criteria.where("messages.lastModifiedDate").gte(lastloginDate),new Criteria().orOperator(Criteria.where("messages.touserId").is(userid),Criteria.where("messages.formuserId").is(userid)))),
//match(new Criteria().andOperator(Criteria.where("messages.lastModifiedDate").is(new BasicDBObject("$gte","ISODate("+format.format(lastloginDate)+")")),new Criteria().orOperator(Criteria.where("messages.touserId").is(userid),Criteria.where("messages.formuserId").is(userid)))),
sort(Direction.DESC, "messages.lastModifiedDate"),
skip(skip),
limit(limit),
group("_id","productId").push("messages").as("data"),
project("_id","productId","data")
//project("product","participants","messages")
);
AggregationResults<Discussion> results = mongoTemplate.aggregate(aggr, "discussion", Discussion.class);
List<Discussion> discussions = results.getMappedResults();
return discussions;
}
I was using a Date field from another document. Changing it to Calendar solved the problem.
// Calling method
Calendar cal = Calendar.getInstance();
cal.setTime(loginInfo.getCreateDate());
return customDiscussionRepository.findInbox(activeUser.getId(), cal.getTime(), pageNumber > 0?pageSize*(pageNumber-1):0, pageSize);
// Repository (lastloginDate is the method argument passed from calling method).
Criteria.where("messages.lastModifiedDate").gte(lastloginDate)
Related
I have a collection which name called 'airport' and i have Atlas Auto Complete index you can see JSON config below.
{
"mappings": {
"dynamic": false,
"fields": {
"name": [
{
"type": "string"
},
{
"foldDiacritics": false,
"maxGrams": 7,
"minGrams": 2,
"type": "autocomplete"
}
]
}
}
}
and this is my Document record
{
"_id": {
"$oid": "63de588c7154cc3ee5cbabb2"
},
"name": "Antalya Airport",
"code": "AYT",
"country": "TR",
"createdDate": {
"$date": {
"$numberLong": "1675516044323"
}
},
"updatedDate": {
"$date": {
"$numberLong": "1675516044323"
}
},
"updatedBy": "VISITOR",
"createdBy": "VISITOR",
}
And This is my MongoDB Query
public List<Document> autoCompleteAirports(AutoCompleteRequest autoCompleteRequest) {
return database.getCollection(AIRPORT).aggregate(
Arrays.asList(new Document("$search",
new Document("index", "airportAutoCompleteIndex")
.append("text",
new Document("query", autoCompleteRequest.getKeyword())
.append("path", "name")
)))
).into(new ArrayList<>());
}
So, when i type "antalya" or "Antalya", this works. But when i type "Antaly" or "antal" there is no result.
Any solution ?
i tried change min and max grams settings on index
I'm using Morphia with MongoDB in Java, and i have collection like this
{"_id":"5d5e7ce7869eef030869e85c",
"ip":"66.249.79.181",
"date":"2019-08-19T18:30:00.000Z",
"request_url":"https://www.example.com/home",
"status_code":"200",
"bot":"Google Android",
"type":"type/html",
"domain":"https://www.example.com"},
{"_id":"5d5e7ce7869eef030869e85c",
"ip":"66.249.79.181",
"date":"2019-08-19T18:30:00.000Z",
"request_url":"https://www.example.com/home",
"status_code":"200",
"bot":"Google",
"type":"type/html",
"domain":"https://www.example.com"},
{"_id":"5d5e7ce7869eef030869e85c",
"ip":"66.249.79.181",
"date":"2019-08-19T18:30:00.000Z",
"request_url":"https://www.example.com/home",
"status_code":"200",
"bot":"bing",
"type":"type/html",
"domain":"https://www.example.com"}
i need to using grouping("request_url") and get count of "bot" field what if I need result like this
{"request_url":"https://www.example.com/home",
"status_code":"200",
"Google": 1,
"Google Android": 1,
"bing": 1,
"type":"type/html", }
How can i do this group by "request_url" Field and get Count of each "bot" Field have
Using aggregate below as:
db.collection.aggregate([
{
$group: {
_id: {
request_url: "$request_url",
bot: "$bot"
},
type: {
$max: "$type"
},
status_code: {
$max: "$status_code"
},
count: {
$sum: 1
}
}
},
{
$group: {
_id: "$_id.request_url",
type: {
$max: "$type"
},
status_code: {
$max: "$status_code"
},
counts: {
$push: {
bot: "$_id.bot",
count: "$count"
}
}
}
}
])
Giving input:
[
{
"ip": "66.249.79.181",
"date": "2019-08-19T18:30:00.000Z",
"request_url": "https://www.example.com/home",
"status_code": "200",
"bot": "Google Android",
"type": "type/html",
"domain": "https://www.example.com"
},
{
"ip": "66.249.79.181",
"date": "2019-08-19T18:30:00.000Z",
"request_url": "https://www.example.com/home",
"status_code": "200",
"bot": "Google",
"type": "type/html",
"domain": "https://www.example.com"
},
{
"ip": "66.249.79.181",
"date": "2019-08-19T18:30:00.000Z",
"request_url": "https://www.example.com/home",
"status_code": "200",
"bot": "bing",
"type": "type/html",
"domain": "https://www.example.com"
}
]
And output being:
[
{
"_id": "https://www.example.com/home",
"counts": [
{
"bot": "bing",
"count": 1
},
{
"bot": "Google",
"count": 1
},
{
"bot": "Google Android",
"count": 1
}
],
"status_code": "200",
"type": "type/html"
}
]
The following query can get us the expected output:
db.collection.aggregate([
{
$group:{
"_id":{
"request_url":"$request_url",
"bot":"$bot"
},
"request_url":{
$first:"$request_url"
},
"k":{
$first:"$bot"
},
"v":{
$sum:1
}
}
},
{
$group:{
"_id":"$request_url",
"request_url":{
$first:"$request_url"
},
"bots":{
$push:{
"k":"$k",
"v":"$v"
}
}
}
},
{
$project:{
"info.request_url":"$request_url",
"bots":{
$arrayToObject:"$bots"
}
}
},
{
$project:{
"info":{
$mergeObjects:["$info","$bots"]
}
}
},
{
$replaceRoot:{
newRoot:"$info"
}
}
]).pretty()
Data set:
{
"_id" : ObjectId("5d6d0f456bc2ad3b23f7dfcf"),
"ip" : "66.249.79.181",
"date" : "2019-08-19T18:30:00.000Z",
"request_url" : "https://www.example.com/home",
"status_code" : "200",
"bot" : "Google Android",
"type" : "type/html",
"domain" : "https://www.example.com"
}
{
"_id" : ObjectId("5d6d0f456bc2ad3b23f7dfd0"),
"ip" : "66.249.79.181",
"date" : "2019-08-19T18:30:00.000Z",
"request_url" : "https://www.example.com/home",
"status_code" : "200",
"bot" : "Google",
"type" : "type/html",
"domain" : "https://www.example.com"
}
{
"_id" : ObjectId("5d6d0f456bc2ad3b23f7dfd1"),
"ip" : "66.249.79.181",
"date" : "2019-08-19T18:30:00.000Z",
"request_url" : "https://www.example.com/home",
"status_code" : "200",
"bot" : "bing",
"type" : "type/html",
"domain" : "https://www.example.com"
}
Output:
{
"request_url" : "https://www.example.com/home",
"bing" : 1,
"Google" : 1,
"Google Android" : 1
}
Explanation: The data is grouped on the request_url and distinct key-value pairs are calculated. The key(k) would hold the bot name and the value(v) would hold the occurrence count. Later on, each pair is pushed into an array and then the array is converted into an object.
I want to group by APPName and I want find how many PrestoBarImpression, PrestoKeyCountChange, PrestoTileImpression for every application for a particular day (just the sum of order counts).
This is so I can generate a report with this information. I need how many order counts of PrestoTileImpression, how many order counts of PrestoBarImpression, how many order counts of PrestoTileClick for every application.
The below is my Document.
{
"ClientId": "XYZ123",
"location": {
"Name": "Hyderabad",
"Country": "India",
"Zip": "500084",
"Gps": {
"lat": "17.463607",
"lon": "78.344279"
}
},
"Network": {
"Operator": "Airtel",
"Type": "wifi",
"TowerID": "123",
"IP": "1.1.1.1"
},
"SessionTimeStamp": {
"Start": ISODate("2015-06-02T05:36:49.045 Z"),
"End": ISODate("2015-06-02T05:36:56.045 Z"),
"Duration": "7000"
},
"AppName": "WhatsApp",
"Text": "Key1 Key2 Key3 Key4",
"Actions": [{
"Type": "PrestoBarImpression",
"CampaignId": 1,
"keyword": "key1",
"prestoCount": 1,
"duration": 100,
"OrderCount": 1
}, {
"Type": "PrestoKeyCountChange",
"CampaignId": 1,
"keyword": "key1",
"prestoCount": 1,
"OrderCount": 2
}, {
"Type": "PrestoBarImpression",
"CampaignId": 2,
"keyword": "key2",
"prestoCount": 2,
"duration": 150,
"OrderCount": 3
}, {
"Type": "PrestoKeyCountChange",
"CampaignId": "2",
"keyword": "key2",
"prestoCount": 2,
"OrderCount": 4
}, {
"Type": "PrestoBarImpression",
"CampaignId": 1,
"keyword": "key3",
"prestoCount": 2,
"duration": 200,
"OrderCount": 5
}, {
"Type": "PrestoTileImpression",
"CampaignId": 1,
"duration": 200,
"OrderCount": 6
}, {
"Type": "PrestoTileImpression",
"AdditionalAction": "swipeRight",
"CampaignId": 2,
"duration": 200,
"OrderCount": 7
}, {
"Type": "PrestoTileClick",
"AdditionalAction": "swipeRight",
"CampaignId": 2,
"OrderCount": 8
}, {
"Type": "PrestoBarImpression",
"CampaignId": 2,
"keyword": "key4",
"prestoCount": 2,
"duration": 150,
"OrderCount": 9
}]
}
I got the below output by using #Viswas response I made a query.
Query
[
{
"$match":{
"SessionTimeStamp.Start":{
"$gte": ISODate("2015-06-01T18:30:00.000 Z"),
"$lte": ISODate("2015-06-04T18:29:59.000 Z")
}
}
},
{
"$unwind":"$Actions"
},
{
"$match":{
"Actions.Type":{
"$in":[
"PrestoBarImpression",
"PrestoKeyCountChange",
"PrestoTileImpression"
]
}
}
},
{
"$group":{
"_id":{
"AppName":"$AppName",
"type":"$Actions.Type"
},
"total":{
"$sum":"$Actions.OrderCount"
}
}
},
{
"$sort":{
"total":1,
}
}
]
Output
{
"result":[
{
"_id":{
"AppName":"WhatsApp",
"type":"PrestoKeyCountChange"
},
"total":6
},
{
"_id":{
"AppName":"hike",
"type":"PrestoKeyCountChange"
},
"total":6
},
{
"_id":{
"AppName":"hike",
"type":"PrestoTileImpression"
},
"total":13
},
{
"_id":{
"AppName":"WhatsApp",
"type":"PrestoTileImpression"
},
"total":13
},
{
"_id":{
"AppName":"hike",
"type":"PrestoBarImpression"
},
"total":18
},
{
"_id":{
"AppName":"WhatsApp",
"type":"PrestoBarImpression"
},
"total":18
}
],
"ok":1.0000000000000000
}
I need the output in below format
[
{
"AppName":"WhatsApp",
" PrestoTileImpression":13,
"PrestoKeyCountChange":6,
"PrestoBarImpression":18,
"count":"10 (This is how many times thee Application presents in document, because I need to find top 10 apps Need to sort the output by this count)"
},
{
"AppName":"Hike",
" PrestoTileImpression":13,
"PrestoKeyCountChange":6,
"PrestoBarImpression":18,
"count":"10 "
}
]
It's really all about filtering the array content to get just the items you want in the sum:
db.collection.aggregate([
// Filter documents with matching entries first
{ "$match": {
"Actions.Type": { "$in": [
"PrestoBarImpression",
"PrestoKeyCountChange",
"PrestoTileImpression"
]}
}},
// Unwind the array entries
{ "$unwind": "$Actions" },
// Filter to only keep desired array entries
{ "$match": {
"Actions.Type": { "$in": [
"PrestoBarImpression",
"PrestoKeyCountChange",
"PrestoTileImpression"
]}
}},
// Group by AppName and current day (finishing)
{ "$group": {
"_id": {
"AppName": "$AppName",
"day": {
"year": { "$year": "$SessionTimeStamp.End" },
"month": { "$month": "$SessionTimeStamp.End" },
"day": { "$dayOfMonth": "$SessionTimeStamp.End" }
},
"type": "$Actions.Type"
},
"total": { "$sum": "$Actions.OrderCount" }
}},
// Sort as however you require
{ "$sort": {
"_id.AppName": 1,
"_id.day": 1,
"_id.type": 1,
"total": -1
}}
])
Or if you want all those fields per document then right after the existing group add:
{ "$group": {
"_id": {
"AppName": "$_id.AppName",
"day": "$_id.day",
},
"PrestoBarImpression": { "$sum": {
"$cond": [
{ "$eq": [ "$_id.type", "PrestoBarImpression" ] },
"$total",
0
]
}},
"PrestoKeyCountChange": { "$sum": {
"$cond": [
{ "$eq": [ "$_id.type", "PrestoKeyCountChange" ] },
"$total",
0
]
}},
"PrestoTileImpression": { "$sum": {
"$cond": [
{ "$eq": [ "$_id.type", "PrestoTileImpression" ] },
"$total",
0
]
}}
}}
Which tallies the totals per field into single documents for "AppName" and "day".
You probably want to add a "date range" match to that first $match pipeline rather than add up everything in the collection and just do so between dates as well.
You should use aggregation to get result.
If you want ActionType wise OrderCount for given date (particular) date then you need to first match start to your date and then group data according to Action.Type.
The query will be as following:
db.collection.aggregate({
$match: {
"SessionTimeStamp.Start": ISODate("2015-06-02T05:36:49.045Z")
}
}, {
$group: {
"_id": "AppName",
"Document": {
$push: {
"SessionTimeStamp": "$SessionTimeStamp",
"Actions": "$Actions",
"AppName": "$AppName"
}
}
}
}, {
$unwind: "$Document"
}, {
$unwind: "$Document.Actions"
}, {
$group: {
_id: "$Document.Actions.Type",
"OrderCount": {
$sum: "$Document.Actions.OrderCount"
},
"App": {
$first: "$Document.AppName"
}
}
}, {
$project: {
"_id": 0,
"OrderCount": 1,
"ActionType": "$_id",
"App": 1
}
})
Edit after comment of question author:
Reference to Duplicate Question by author
Please verify spelling of count for appNames as it is different (count, Count) for some appNames
You should use following query-
db.collection.aggregate({
$match: {
"SessionTimeStamp.Start": {
$gte: ISODate("2015-06-02T05:36:49.045Z")
},
"SessionTimeStamp.End": {
$lte: ISODate("2015-06-02T05:36:56.045Z")
}
}
}, {
$unwind: "$Actions"
}, {
$group: {
"_id": {
"AppName": "$AppName",
"Type": "$Actions.Type"
},
"count": {
"$sum": "$Actions.Count"
},
"appCount": {
$sum: 1
}
}
}, {
$project: {
"AppName": "$_id.AppName",
"Type": "$_id.Type",
"count": 1,
"appCount": 1,
"_id": 0
}
})
If you still want to assign dynamic values as keys then you can iterate over the cursor you get like -
db.collection.aggregate({$match:{"SessionTimeStamp.Start":{$gte:ISODate("2015-06-02T05:36:49.045Z")},
"SessionTimeStamp.End":{$lte:ISODate("2015-06-02T05:36:56.045Z")}}},
{$unwind:"$Actions"},{$group:{"_id":{"AppName":"$AppName","Type":"$Actions.Type"},
"count":{"$sum":"$Actions.Count"},"appCount":{$sum:1}}},
{$project:{"AppName":"$_id.AppName","Type":"$_id.Type","count":1,
"appCount":1,"_id":0}}).forEach( function(myDoc){ var feeType = {};
feeType["AppName"] = myDoc.AppName; feeType[myDoc.Type]= myDoc.count;
feeType["appCount"] = myDoc.appCount; printjson (feeType);})
I need to export customer records from database of mongoDB. Exported customer records should not have duplicated values. "firstName+lastName+code" is the key to DE-duped the record and If there are two records present in database with same key then I need to give preference to source field with value other than email.
customer (id,firstName,lastName,code,source) collection is this.
If there are record 3 records with same unique key and 3 different sources then i need to choose only one record between 2 sources(TV,internet){or if there are n number of sources i need the one record only}not with the 'email'(as email will be choosen when only one record is present with the unique key and source is email)
query using:
db.customer.aggregate([
{
"$match": {
"active": true,
"dealerCode": { "$in": ["111391"] },
"source": { "$in": ["email", "TV", "internet"] }
}
},
{
$group: {
"_id": {
"firstName": "$personalInfo.firstName",
"lastName": "$personalInfo.lastName",
"code": "$vehicle.code"
},
"source": {
$addToSet: { "source": "$source" }
}
}
},
{
$redact:
{
$cond: [
{ $eq: [{ $ifNull: ["$source", "other"] }, "email"] },
"$$PRUNE",
"$$DESCEND"
]
}
},
{
$project:
{
"source":
{
$map:
{
"input": {
$cond: [
{ $eq: [{ $size: "$source" }, 0] },
[{ "source": "email" }],
"$source"
]
},
"as": "inp",
"in": "$$inp.source"
}
},
"record": { "_id": 1 }
}
}
])
sample output:
{ "_id" : { "firstName" : "sGI6YaJ36WRfI4xuJQzI7A==", "lastName" : "99eQ7i+uTOqO8X+IPW+NOA==", "code" : "1GTHK23688F113955" }, "source" : ["internet"] }
{ "_id" : { "firstName" : "WYDROTF/9vs9O7XhdIKd5Q==", "lastName" : "BM18Uq/ltcbdx0UJOXh7Sw==", "code" : "1G4GE5GV5AF180133" }, "source" : ["internet"] }
{ "_id" : { "firstName" : "id+U2gYNHQaNQRWXpe34MA==", "lastName" : "AIs1G33QnH9RB0nupJEvjw==", "code" : "1G4GE5EV0AF177966" }, "source" : ["internet"] }
{ "_id" : { "firstName" : "qhreJVuUA5l8lnBPVhMAdw==", "lastName" : "petb0Qx3YPfebSioY0wL9w==", "code" : "1G1AL55F277253143" }, "source" : ["TV"] }
{ "_id" : { "firstName" : "qhreJVuUA5l8lnBPVhMAdw==", "lastName" : "6LB/NmhbfqTagbOnHFGoog==", "code" : "1GCVKREC0EZ168134" }, "source" : ["TV", "internet"] }
This is a problem with this query please suggest :(
Your code doesn't work, because $cond is not an accumulator operator. Only these accumulator operators, can be used in a $group stage.
Assuming your records contain not more than two possible values of source as you mention in your question, you could add a conditional $project stage and modify the $group stage as,
Code:
db.customer.aggregate([
{
$group: {
"_id": {
"id": "$id",
"firstName": "$firstName",
"lastName": "$lastName",
"code": "$code"
},
"sourceA": { $first: "$source" },
"sourceB": { $last: "$source" }
}
},
{
$project: {
"source": {
$cond: [
{ $eq: ["$sourceA", "email"] },
"$sourceB",
"$sourceA"
]
}
}
}
])
In case there can be more that two possible values for source, then you could do the following:
Group by the id, firstName, lastName and code. Accumulate
the unique values of source, using the $addToSet operator.
Use $redact to keep only the values other than email.
Project the required fields, if the source array is empty(all the elements have been removed), add a
value email to it.
Unwind the source field to list it as a field and not an array.
(optional)
Code:
db.customer.aggregate([
{
$group: {
"_id": {
"id": "$id",
"firstName": "$firstName",
"lastName": "$lastName",
"code": "$code"
},
"sourceArr": { $addToSet: { "source": "$source" } }
}
},
{
$redact: {
$cond: [
{ $eq: [{ $ifNull: ["$source", "other"] }, "email"] },
"$$PRUNE",
"$$DESCEND"
]
}
},
{
$project: {
"source": {
$map: {
"input":
{
$cond: [
{ $eq: [{ $size: "$sourceArr" }, 0] },
[{ "source": "item" }],
"$sourceArr"]
},
"as": "inp",
"in": "$$inp.source"
}
}
}
}
])
This is my index mapping
"index":{
"mappings":{
"patient":{
"properties":{
"LastName":{
"type":"string"
},
"accountType":{
"type":"string"
},
"civilStatus":{
"type":"string"
},
"consultations":{
"type":"nested",
"properties":{
"deleted":{
"type":"boolean"
},
"diagnosis":{
"type":"string",
"index":"not_analyzed"
},
"documentDate":{
"type":"date",
"format":"dateOptionalTime"
},
"firstName":{
"type":"string"
},
"lastName":{
"type":"string"
},
"middleName":{
"type":"string"
},
"prescriptions":{
"type":"string"
}
}
},
"firstName":{
"type":"string"
},
"gender":{
"type":"string"
},
"id":{
"type":"string",
"index":"not_analyzed"
},
"lastName":{
"type":"string"
},
"middleName":{
"type":"string"
},
"occupation":{
"type":"string"
},
"owner":{
"type":"string",
"index":"not_analyzed"
},
"patientPin":{
"type":"string"
}
}
}
}
}
}
Here's the only saved data on ElasticSearch
{
"_index":"index",
"_type":"patient",
"_id":"TENANT1100066",
"_score":1.0,
"_source":{
"id":"100066",
"firstName":"Johnny",
"patientPin":"201408000001",
"middleName":"John ",
"consultations":[
{
"id":null,
"prescriptions":[
],
"diagnosis":[
"headache of unknown origin"
],
"documentDate":"2014-08-05T10:10:00.000+08:00",
"deleted":false,
"lastName":"David",
"firstName":"Johnny ",
"middleName":"John "
}
],
"owner":"TENANT1",
"gender":"MALE",
"occupation":"Unspecified",
"accountType":"INDIVIDUAL",
"civilStatus":"SINGLE",
"lastName":"David"
}
}
And here's the sample query I built to check how boolean query works.
{
"nested" : {
"query" : {
"bool" : {
"must" : [ {
"match" : {
"consultations.diagnosis" : {
"query" : "Kawasaki's Disease",
"type" : "phrase"
}
}
}, {
"match" : {
"consultations.diagnosis" : {
"query" : "Alcohol Intoxication",
"type" : "phrase"
}
}
} ],
"must_not" : {
"match" : {
"consultations.deleted" : {
"query" : "true",
"type" : "boolean"
}
}
},
"should" : {
"match" : {
"consultations.diagnosis" : {
"query" : "headache of unknown origin",
"type" : "phrase"
}
}
}
}
},
"path" : "consultations"
}
Apparently, Kawasaki's Disease and Fibriasis does not exist but headache of unknown origin exists but no
results are returned(Which is Johnny John David) what am I missing here? The operation I had in my mind was
(Kawasaki's Disease AND Fibriasis) OR headache of unknown origin.
What I had in mind was if there was no patients with Kawasakis Disease AND Fibriasis search for Patients with "headache of unknown origin". Which clearly we have, but my query is returning 0 results. what Am I missing here
In your query, you require that matching documents have both (Kawasaki's Disease AND Fibriasis) as you added these 2 conditions in the must clause.
Your document only match your should clause, so it doesn't appear in the search results.
To achieve what you want :
(Kawasaki's Disease AND Fibriasis) OR headache of unknown origin
You can embed the two diseases in another bool query and add this query in the should section of the root query, like this :
{
"query": {
"nested": {
"path": "consultations",
"query": {
"bool": {
"should": [
{
"bool": {
"must": [{
"match_phrase": {
"consultations.diagnosis": "Kawasaki's Disease"
}
},
{
"match_phrase": {
"consultations.diagnosis": "Alcohol Intoxication"
}
}
]
}
},
{
"match_phrase": {
"consultations.diagnosis": "headache of unknown origin"
}
}
],
"minimum_number_should_match": 1
}
}
}
}
}
Which outputs the previously indexed patient :
{
"took": 2,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 1,
"max_score": 0.3007646,
"hits": [
{
"_index": "test",
"_type": "patient",
"_id": "TENANT1100066",
"_score": 0.3007646,
"_source": {
"id": "100066",
"firstName": "Johnny",
"patientPin": "201408000001",
"middleName": "John ",
"consultations": [
{
"id": null,
"prescriptions": [],
"diagnosis": [
"headache of unknown origin"
],
"documentDate": "2014-08-05T10:10:00.000+08:00",
"deleted": false,
"lastName": "David",
"firstName": "Johnny ",
"middleName": "John "
}
],
"owner": "TENANT1",
"gender": "MALE",
"occupation": "Unspecified",
"accountType": "INDIVIDUAL",
"civilStatus": "SINGLE",
"lastName": "David"
}
}
]
}
}