Mongodb query select embedded document - mongodb

I have following Mongodb document. Would like to fetch document where participant = 'xxx' and (message.touserid = 'xxx' or message.fromuserid = 'xxx').
I am using following query but it is returning all messages instead of just one. Could you please let me know how to achieve this result?
{ "$and" : [ { "participants" : { "$regex" : "56d314a8e4b04d7f98cfd0c6"} , "$or" : [ { "messages.touserId" : "56d314a8e4b04d7f98cfd0c6"} , { "messages.formuserId" : "56d314a8e4b04d7f98cfd0c6"}]}]} fields: { "_id" : "0" , "product" : "0" , "participants" : "0" , "messages" : "0"}
{
"_id": {
"$oid": "574eb878027520c2158268d6"
},
"_class": "com.idearealty.product.shopchat.persistence.model.Discussion",
"participants": "56d314a8e4b04d7f98cfd0c6,56d5d48ee4b0cc330f512a47,56d9d599e4b0cc330f512aaa,57130299e4b08c554c1092c7,56841002eceefce22f455c7f",
"messages": [
{
"_id": {
"$oid": "574eb874027520c2158268d2"
},
"formuserId": "56841002eceefce22f455c7f",
"fromuser": "9674642375",
"touserId": "56d314a8e4b04d7f98cfd0c6",
"touser": "debopam_r",
"message": "Creating Discussion",
"isMute": false,
"index": 1,
"createDate": {
"$date": "2016-06-01T10:27:00.500Z"
},
"lastModifiedDate": {
"$date": "2016-06-01T10:27:00.501Z"
},
"createdBy": "9674642375",
"lastModifiedBy": "9674642375"
},
{
"_id": {
"$oid": "574eb875027520c2158268d3"
},
"formuserId": "56841002eceefce22f455c7f",
"fromuser": "9674642375",
"touserId": "56d5d48ee4b0cc330f512a47",
"touser": "Raushan",
"message": "Creating Discussion",
"isMute": false,
"index": 2,
"createDate": {
"$date": "2016-06-01T10:27:01.295Z"
},
"lastModifiedDate": {
"$date": "2016-06-01T10:27:01.295Z"
},
"createdBy": "9674642375",
"lastModifiedBy": "9674642375"
},
{
"_id": {
"$oid": "574eb875027520c2158268d4"
},
"formuserId": "56841002eceefce22f455c7f",
"fromuser": "9674642375",
"touserId": "56d9d599e4b0cc330f512aaa",
"touser": "anirbanshop1",
"message": "Creating Discussion",
"isMute": false,
"index": 3,
"createDate": {
"$date": "2016-06-01T10:27:01.962Z"
},
"lastModifiedDate": {
"$date": "2016-06-01T10:27:01.962Z"
},
"createdBy": "9674642375",
"lastModifiedBy": "9674642375"
},
{
"_id": {
"$oid": "574eb876027520c2158268d5"
},
"formuserId": "56841002eceefce22f455c7f",
"fromuser": "9674642375",
"touserId": "57130299e4b08c554c1092c7",
"touser": "dummyshop",
"message": "Creating Discussion",
"isMute": false,
"index": 4,
"createDate": {
"$date": "2016-06-01T10:27:02.574Z"
},
"lastModifiedDate": {
"$date": "2016-06-01T10:27:02.574Z"
},
"createdBy": "9674642375",
"lastModifiedBy": "9674642375"
}
],
"messageCount": 4,
"createDate": {
"$date": "2016-06-01T10:27:04.041Z"
},
"lastModifiedDate": {
"$date": "2016-06-01T10:27:04.041Z"
},
"createdBy": "9674642375",
"lastModifiedBy": "9674642375"
}

As this is a complex match on elements - $elemMatch cannot be used in this case,
so aggregation framework is a helper.
var match = {
$match : {
participants : /56d314a8e4b04d7f98cfd0c6/
}
}
var unwind = {
$unwind : "$messages"
}
var matchSecond = {
$match : {
$or : [{
"messages.touserId" : "56d314a8e4b04d7f98cfd0c6"
}, {
"messages.formuserId" : "56d314a8e4b04d7f98cfd0c6"
}
]
}
}
var projection = {
$project : {
_id : 0,
messages : 1
}
}
db.deb.aggregate([match, unwind, matchSecond, projection])
and output:
{
"messages" : {
"_id" : {
"oid" : "574eb874027520c2158268d2"
},
"formuserId" : "56841002eceefce22f455c7f",
"fromuser" : "9674642375",
"touserId" : "56d314a8e4b04d7f98cfd0c6",
"touser" : "debopam_r",
"message" : "Creating Discussion",
"isMute" : false,
"index" : 1.0,
"createDate" : {
"date" : "2016-06-01T10:27:00.500Z"
},
"lastModifiedDate" : {
"date" : "2016-06-01T10:27:00.501Z"
},
"createdBy" : "9674642375",
"lastModifiedBy" : "9674642375"
}
}

Related

Access Nested Objects using Painless for Elasticsearch/Opensearch Alerting to Create Trigger Condition

I tried creating Trigger condition in Monitor in Opensearch.I was trying to extract fields present in _source which is giving error "reason" : "Illegal list shortcut value [_source].".
DSL Extraction Query-
{
"size": 1,
"sort": {"Date" : "desc" },
"query": {
"bool": {
"filter": [
{
"range": {
"Date": {
"from": "{{period_end}}||-3d",
"to": "{{period_end}}",
"include_lower": true,
"include_upper": true,
"format": "epoch_millis",
"boost": 1
}
}
}
],
"adjust_pure_negative": true,
"boost": 1
}
},
"aggregations": {
"metric": {
"avg": {
"field": "difference"
}
}
}
}
Output-
{
"_shards": {
"total": 4,
"failed": 0,
"successful": 4,
"skipped": 2
},
"hits": {
"hits": [
{
"_index": "reliance_cal_spread",
"_source": {
"symbol": "RELIANCE",
"std_dev": 2.4,
"upper_range": 10.3,
"current_month_close": 2536.3,
"mean": 7.9,
"weekday": "Tuesday",
"difference": 3,
"Date": "2022-06-28T00:00:00",
"next_month_close": 2539.3,
"lower_range": 5.5
},
"_id": "E2-cqoEB0vMP3J-sGCIB",
"sort": [
1656374400000
],
"_score": null
}
],
"total": {
"value": 2,
"relation": "eq"
},
"max_score": null
},
"took": 8,
"timed_out": false,
"aggregations": {
"metric": {
"value": 2.799999952316284
}
}
}
Trigger Condition-
return ctx.results[0].aggregations.metric.value == null ? false :ctx.results[0].hits.hits._source.difference > 6
Error-
{
"type" : "script_exception",
"reason" : "runtime error",
"script_stack" : [
"return ctx.results[0].aggregations.metric.value == null ? false :ctx.results[0].hits.hits._source.difference > 6",
" ^---- HERE"
],
"script" : "return ctx.results[0].aggregations.metric.value == null ? false :ctx.results[0].hits.hits._source.difference > 6",
"lang" : "painless",
"position" : {
"offset" : 89,
"start" : 0,
"end" : 112
},
"caused_by" : {
"type" : "illegal_argument_exception",
"reason" : "Illegal list shortcut value [_source]."
}
}
While I am able to extract other conditions such as-aggregations.metric.value and hits.total.value.
Trigger Condition
return ctx.results[0].aggregations.metric.value == null ? false :ctx.results[0].aggregations.metric.value < 6
Trigger Condition Response-
True

Matching a value in subdocument array and matching array to _id

I have a collection of Users which looks like this:
{
"_id": {
"$oid": "5ff6298f2056ad02272d10f2"
},
"name": "Billy Bob",
"story": {
"posts": [
{"id": "b4a12557-4dfa-47eb-9f27-7bbcad0f4c45"},
{"id": "b4a12557-4dfa-47eb-9f27-7bbcad0f4c45"},
{"id": "b4a12557-4dfa-47eb-9f27-7bbcad0f4c45"}
],
"whoCanView": [{
"$oid": "5ff891bd749ed24316272317"
}, {
"$oid": "5ffc89392056ad02272d10f3"
}]
}
}
I want to get all users and their stories listed in an array which I call "contacts". The user currently querying the collection may only get results if their userId is in the "whoCanView" array.
This is what i have so far but doesn't seem to be working:
users.find({'story' : {
'$elementMatch' : {
'_id' : {'$in' : contacts},
ObjectID(userId) : {'$in' : 'story.whoCanView'}
}
}
});
Any guidance would be appreciated. Thanks!
ObjectID(userId) : {'$in' : 'story.whoCanView'}
Above line along with the usage of $elemMatch operator is wrong in your code. Try this query instead:
let contacts = [
ObjectId("5ff6298f2056ad02272d10f2"),
ObjectId("5ff6298f2056ad02272d10f3"),
ObjectId("5ff6298f2056ad02272d10f4")
];
let userId = ObjectId("5ff891bd749ed24316272317");
db.users.find(
{
"_id": { $in: contacts },
"story.whoCanView": userId
},
{
"strories": "$story.posts"
}
);
Output when userId is ObjectId("5ff891bd749ed24316272317"):
/* 1 createdAt:1/7/2021, 2:50:15 AM*/
{
"_id" : ObjectId("5ff6298f2056ad02272d10f2"),
"strories" : [
{
"id" : "b4a12557-4dfa-47eb-9f27-7bbcad0f4c45"
},
{
"id" : "b4a12557-4dfa-47eb-9f27-7bbcad0f4c45"
},
{
"id" : "b4a12557-4dfa-47eb-9f27-7bbcad0f4c45"
}
]
},
/* 2 createdAt:1/7/2021, 2:50:15 AM*/
{
"_id" : ObjectId("5ff6298f2056ad02272d10f3"),
"strories" : [
{
"id" : "b4a12557-4dfa-47eb-9f27-7bbcad0f4c45"
},
{
"id" : "b4a12557-4dfa-47eb-9f27-7bbcad0f4c45"
},
{
"id" : "b4a12557-4dfa-47eb-9f27-7bbcad0f4c45"
}
]
},
/* 3 createdAt:1/7/2021, 2:50:15 AM*/
{
"_id" : ObjectId("5ff6298f2056ad02272d10f4"),
"strories" : [
{
"id" : "b4a12557-4dfa-47eb-9f27-7bbcad0f4c45"
},
{
"id" : "b4a12557-4dfa-47eb-9f27-7bbcad0f4c45"
},
{
"id" : "b4a12557-4dfa-47eb-9f27-7bbcad0f4c45"
}
]
}
Output when userId is ObjectId("5ff891bd749ed24316272318"):
[]
Test data in users collection:
[
{
"_id": ObjectId("5ff6298f2056ad02272d10f2"),
"name": "Billy Bob",
"story": {
"posts": [
{ "id": "b4a12557-4dfa-47eb-9f27-7bbcad0f4c45" },
{ "id": "b4a12557-4dfa-47eb-9f27-7bbcad0f4c45" },
{ "id": "b4a12557-4dfa-47eb-9f27-7bbcad0f4c45" }
],
"whoCanView": [
ObjectId("5ff891bd749ed24316272317"),
ObjectId("5ffc89392056ad02272d10f3")
]
}
},
{
"_id": ObjectId("5ff6298f2056ad02272d10f3"),
"name": "Billy Bob",
"story": {
"posts": [
{ "id": "b4a12557-4dfa-47eb-9f27-7bbcad0f4c45" },
{ "id": "b4a12557-4dfa-47eb-9f27-7bbcad0f4c45" },
{ "id": "b4a12557-4dfa-47eb-9f27-7bbcad0f4c45" }
],
"whoCanView": [
ObjectId("5ff891bd749ed24316272317"),
ObjectId("5ffc89392056ad02272d10f3")
]
}
},
{
"_id": ObjectId("5ff6298f2056ad02272d10f4"),
"name": "Billy Bob",
"story": {
"posts": [
{ "id": "b4a12557-4dfa-47eb-9f27-7bbcad0f4c45" },
{ "id": "b4a12557-4dfa-47eb-9f27-7bbcad0f4c45" },
{ "id": "b4a12557-4dfa-47eb-9f27-7bbcad0f4c45" }
],
"whoCanView": [
ObjectId("5ff891bd749ed24316272317"),
ObjectId("5ffc89392056ad02272d10f3")
]
}
},
{
"_id": ObjectId("5ff6298f2056ad02272d10f5"),
"name": "Billy Bob",
"story": {
"posts": [
{ "id": "b4a12557-4dfa-47eb-9f27-7bbcad0f4c45" },
{ "id": "b4a12557-4dfa-47eb-9f27-7bbcad0f4c45" },
{ "id": "b4a12557-4dfa-47eb-9f27-7bbcad0f4c45" }
],
"whoCanView": [
ObjectId("5ff891bd749ed24316272317"),
ObjectId("5ffc89392056ad02272d10f3")
]
}
}
]

Mongo Filter Query Nested with mulitple and

Following is my query does exactly match with my document but still not getting output.Don't know why. Following is the document as well.
db.getCollection("analytics").find(
{
"$and" : [
{
"archive" : false
},
{
"platform" : "WEB"
},
{
"vendorId" : "3c7adbfe-14d7-4b26-9134-7e05d56573cc"
},
{
"createdAt" : {
"$gte" : 1578268800000.0
}
},
{
"createdAt" : {
"$lte" : 1580860800000.0
}
},
{
"$and" : [
{
"data.mobile" : "123"
},
{
"page" : "Loan Application"
},
{
"event" : "click"
}
]
},
{
"$and" : [
{
"data.aadharNumber" : "123"
},
{
"page" : "Personal Information"
},
{
"event" : "click"
}
]
},
{
"$and" : [
{
"data.totalExp" : "5"
},
{
"page" : "Professional Information"
},
{
"event" : "click"
}
]
}
]
}
);
Documents :
[
{
"page": "Loan Application",
"event": "click",
"loggedIn": true,
"vendorId": "3c7adbfe-14d7-4b26-9134-7e05d56573cc",
"data": {
"first": "Praveen",
"mobile": "1234"
},
"platform": "WEB"
},
{
"page": "Personal Information",
"event": "click",
"loggedIn": true,
"vendorId": "3c7adbfe-14d7-4b26-9134-7e05d56573cc",
"data": {
"panNumber": "123",
"aadharNumber": "123"
},
"platform": "WEB"
},
{
"page": "Professional Information",
"event": "click",
"loggedIn": true,
"vendorId": "3c7adbfe-14d7-4b26-9134-7e05d56573cc",
"data": {
"totalExp": "5"
},
"platform": "WEB"
}
]
There are a lot of issues going on with your query, you can try below query to return all documents :
db.getCollection("analytics").find({
$expr: {
$and: [
{
$eq: [
"$platform",
"WEB"
]
},
{
$eq: [
"$vendorId",
"3c7adbfe-14d7-4b26-9134-7e05d56573cc"
]
},
{
$or: [
{
"$and": [
{
"data": {
"mobile": "123"
}
},
{
"page": "Loan Application"
},
{
"event": "click"
}
]
},
{
"$and": [
{
"data": {
"aadharNumber": "123"
}
},
{
"page": "Personal Information"
},
{
"event": "click"
}
]
},
{
"$and": [
{
"data": {
"totalExp": "5"
}
},
{
"page": "Professional Information"
},
{
"event": "click"
}
]
}
]
}
]
}
})
Test : MongoDB-Playground

Aggregate and grouping in Mongo

How do I get a summary count in Mongo. I have the following record structure and I would like to get a summary by date and status
{
"_id": "1",
"History": [
{
"id": "11",
"message": "",
"status": "send",
"resultCount": 0,
"createdDate": "",
"modifiedDate": ""
},
{
"id": "21",
"message": "",
"status": "skipped",
"resultCount": 0,
"createdDate": "",
"modifiedDate": ""
}
]
}
This is what I would like..
date x
status :
count : nn
This is my Mongo structure
Let's assume you have the following data in 'history' collection:
{
"_id": "1",
"History": [
{
"id": "21",
"message": "",
"status": "send",
"resultCount": 0,
"createdDate": "date1",
"modifiedDate": ""
},
{
"id": "22",
"message": "",
"status": "skipped",
"resultCount": 0,
"createdDate": "date1",
"modifiedDate": ""
},
{
"id": "23",
"message": "",
"status": "skipped",
"resultCount": 0,
"createdDate": "date2",
"modifiedDate": ""
},
{
"id": "24",
"message": "",
"status": "skipped",
"resultCount": 0,
"createdDate": "date2",
"modifiedDate": ""
}
]
}
You can design your query in the following way to get the desired summary.
db.history.aggregate([
{
$unwind:"$History"
},
{
$group:{
"_id":{
"createdDate":"$History.createdDate",
"status":"$History.status"
},
"createdDate":{
$first: "$History.createdDate"
},
"status":{
$first:"$History.status"
},
"count":{
$sum:1
}
}
},
{
$group:{
"_id":"$createdDate",
"createdDate":{
$first:"$createdDate"
},
"info":{
$push:{
"status":"$status",
"count":"$count"
}
}
}
},
{
$project:{
"_id":0
}
}
]).pretty()
It would result in the following:
{
"createdDate" : "date1",
"info" : [
{
"status" : "skipped",
"count" : 1
},
{
"status" : "send",
"count" : 1
}
]
}
{
"createdDate" : "date2",
"info" : [
{
"status" : "skipped",
"count" : 2
}
]
}
Aggregation stages details:
Stage I: The 'History' array is unwinded i.e. the array would be split and each element would create an individual document.
Stage II: The data is grouped on the basis of 'createdDate' and 'status'. In this stage, the count of status is also calculated.
Stage III: The data is further grouped on the basis of 'createdDate'
only
Stage IV: Eliminating non-required fields from the result

Join on Related properties of two Arrays

I have the following result. Below it would be possible to make a map joining the array each with its objectid.
{
"_id": ObjectId("597233b50e717e0585dbd94a"),
"createdAt": ISODate("2017-07-21T17:02:45.119+0000"),
"name": "cardoso",
"gender": "female",
"profile": [{
"profession": "master",
"_id": ObjectId("597233b50e717e0585dbd94b"),
"departament": ObjectId("597233b50e717e0585dbd94e")
},
{
"_id": ObjectId("59766719003e7d552fe40e8c"),
"profession": "master",
"departament": ObjectId("59766719003e7d552fe40e8b")
},
{
"_id": ObjectId("5976b8f99d8a4326c6bf1ae5"),
"profession": "master",
"departament": ObjectId("5974d8fe398e5b2fd433410f")
}
],
"Institution": {
"_id": ObjectId("597233b50e717e0585dbd94c"),
"cnpj": 64837134000144.0,
"deletedAt": false,
"departament": [{
"title": "cardoso",
"category": "Sub-17",
"_id": ObjectId("597233b50e717e0585dbd94e")
},
{
"sport": "Tênis",
"title": "novo",
"category": "Sub-12",
"_id": ObjectId("59766719003e7d552fe40e8b")
},
{
"_id": ObjectId("5974d8fe398e5b2fd433410f"),
"category": "Intercâmbio",
"title": "testeJJJ",
"sport": "natação"
}
]
}
}
I need to do the following result. I did not want to have to manipulate the result in the node.
{
"sport": "Tênis",
"profession": "master",
"title": "novo",
"category": "Sub-12",
"_id": ObjectId("59766719003e7d552fe40e8b")
}
I already tended to do something but the query ends up getting very big
The basic premise here is to "lookup" the content in the other array whilst processing via $map.
This is either done via $indexOfArray with MongoDB 3.4:
db.collection.aggregate([
{ "$addFields": {
"Institution": {
"departament": {
"$map": {
"input": "$Institution.departament",
"as": "d",
"in": {
"sport": "$$d.title",
"profession": {
"$arrayElemAt": [
"$profile.profession",
{ "$indexOfArray": [ "$profile.departament", "$$d._id" ] }
]
},
"title": "$$d.title",
"category": "$$d.category"
}
}
}
}
}}
])
In that first index we look for the "index position" from the "profile" array that matches the current value of _id on the specified field. Then extract the data at that index via $arrayElemAt.
Or using $filter and the $arrayElemAt "the other way around" with MongoDB 3.2:
db.collection.aggregate([
{ "$addFields": {
"Institution": {
"departament": {
"$map": {
"input": "$Institution.departament",
"as": "d",
"in": {
"sport": "$$d.title",
"profession": {
"$arrayElemAt": [
{ "$map": {
"input": {
"$filter": {
"input": "$profile",
"as": "p",
"cond": { "$eq": [ "$$p.departament", "$$d._id" ] }
}
},
"as": "p",
"in": "$$p.profession"
}},
0
]
},
"title": "$$d.title",
"category": "$$d.category"
}
}
}
}
}}
])
In which case the $filter reduces the array content in "profile" down to only matching elements, which should be just one. This is then extracted at the 0 index by $arrayElemAt.
Same result in either case:
{
"_id" : ObjectId("597233b50e717e0585dbd94a"),
"createdAt" : ISODate("2017-07-21T17:02:45.119Z"),
"name" : "cardoso",
"gender" : "female",
"profile" : [
{
"profession" : "master",
"_id" : ObjectId("597233b50e717e0585dbd94b"),
"departament" : ObjectId("597233b50e717e0585dbd94e")
},
{
"_id" : ObjectId("59766719003e7d552fe40e8c"),
"profession" : "master",
"departament" : ObjectId("59766719003e7d552fe40e8b")
},
{
"_id" : ObjectId("5976b8f99d8a4326c6bf1ae5"),
"profession" : "master",
"departament" : ObjectId("5974d8fe398e5b2fd433410f")
}
],
"Institution" : {
"_id" : ObjectId("597233b50e717e0585dbd94c"),
"cnpj" : 64837134000144.0,
"deletedAt" : false,
"departament" : [
{
"sport" : "cardoso",
"profession" : "master",
"title" : "cardoso",
"category" : "Sub-17"
},
{
"sport" : "novo",
"profession" : "master",
"title" : "novo",
"category" : "Sub-12"
},
{
"sport" : "testeJJJ",
"profession" : "master",
"title" : "testeJJJ",
"category" : "Intercâmbio"
}
]
}
}