Mongo Error QueryExceededMemoryLimitNoDiskUseAllowed - database

Getting this error, when I am using this query:
db2.collection('candata')
.aggregate([{$sort:{time:-1}},{$group:{_id:{batteryId:"$batteryId"},soctime:{$first:"$time"},GPSStatus:{$first:"$GPSStatus"},CANStatus:{$first:"$CANStatus"},soc: { $first : "$socpercentage" },charging_status: { $first : "$charging_status" },status: { $first : "$status" }}},{$sort:{'_id.batteryId':1}},{$lookup:{from : "swap_table",localField : "_id.batteryId",foreignField:"batteryId",as:"swap"}},{$lookup:{from : "battery_status_table",localField : "_id.batteryId",foreignField:"batteryId",as:"battery_statustb"}}])
What change do I need to do? I do not want to change the query, so how to increase the limit of this, or I need to go some data archived method?

Add allowDiskUse and set it to true at the end of your query so it becomes like the following:
db2.collection('candata')
.aggregate([{$sort:{time:-1}},{$group:{_id:{batteryId:"$batteryId"},soctime:{$first:"$time"},GPSStatus:{$first:"$GPSStatus"},CANStatus:{$first:"$CANStatus"},soc: { $first : "$socpercentage" },charging_status: { $first : "$charging_status" },status: { $first : "$status" }}},{$sort:{'_id.batteryId':1}},{$lookup:{from : "swap_table",localField : "_id.batteryId",foreignField:"batteryId",as:"swap"}},{$lookup:{from : "battery_status_table",localField : "_id.batteryId",foreignField:"batteryId",as:"battery_statustb"}}]).allowDiskUse(true)

Add allowDiskUse with second params of aggregate function, like this:
agg = [{$sort:{time:-1}},{$group:{_id:{batteryId:"$batteryId"},soctime:{$first:"$time"},GPSStatus:{$first:"$GPSStatus"},CANStatus:{$first:"$CANStatus"},soc: { $first : "$socpercentage" },charging_status: { $first : "$charging_status" },status: { $first : "$status" }}},{$sort:{'_id.batteryId':1}},{$lookup:{from : "swap_table",localField : "_id.batteryId",foreignField:"batteryId",as:"swap"}},{$lookup:{from : "battery_status_table",localField : "_id.batteryId",foreignField:"batteryId",as:"battery_statustb"}}]
db2.collection('candata').aggregate(agg, allowDiskUse=True)

you can add allowDiskUse with second of aggregate function eg:
db.getCollection("loans_unique").aggregate([{
"$group": {
"_id": {
phone: "$phone",
address: "$address",
title: "$title"
},
"count": {
"$sum": 1
}
}
},
{
$sort: {
"count": -1
}
},
{
$match: {
"count": {$gt: 1}
}
}
], {
allowDiskUse: true
})

Related

MongoDB merge Array Elements inside an Array

I have a collection.
{
"_id" : "410a7cb2-7ee1-4e7a-9fb7-fa651fcaa4e5",
"reqHistoryEvents" : [
{
"reqHistoryMsg" : "abcd",
"reqHistoryCreatedAt" : ISODate("2022-04-27T08:18:30.850+0000"),
},
{
"reqHistoryMsg" : "EFGH ",
"reqHistoryCreatedAt" : ISODate("2022-04-27T08:22:12.716+0000"),
},
{
"reqHistoryMsg" : "IJKL",
"reqHistoryCreatedAt" : ISODate("2022-04-27T08:22:12.716+0000"),
}
]
}
I want to convert it to this :::::
{
"_id" : "410a7cb2-7ee1-4e7a-9fb7-fa651fcaa4e5",
"reqHistoryEvents" : [
{
"reqHistoryMsg" : "abcd",
"reqHistoryCreatedAt" : ISODate("2022-04-27T08:18:30.850+0000"),
},
{
"reqHistoryMsg" : ["EFGH ","IJKL"],
"reqHistoryCreatedAt" : ISODate("2022-04-27T08:22:12.716+0000"),
}
]
}
Basically it will be based on the creation Timestamp. We need to merge the reqHistoryMsg if we have same reqHistoryCreatedAt.
I am not able to write the mongo query. Any help?
$unwind - Deconstruct reqHistoryEvents array field.
$group - Group by _id and reqHistoryEvents.reqHistoryCreatedAt fields. Add reqHistoryMsg into an array.
$group - Group by _id field and form reqHistoryEvents array.
db.collection.aggregate([
{
$unwind: "$reqHistoryEvents"
},
{
$group: {
_id: {
_id: "$_id",
reqHistoryCreatedAt: "$reqHistoryEvents.reqHistoryCreatedAt"
},
reqHistoryMsg: {
$push: "$reqHistoryEvents.reqHistoryMsg"
}
}
},
{
$group: {
_id: "$_id._id",
reqHistoryEvents: {
$push: {
reqHistoryMsg: "$reqHistoryMsg",
reqHistoryCreatedAt: "$_id.reqHistoryCreatedAt"
}
}
}
}
])
Sample Mongo Playground

Write a mongo query to count the data where similar data in array?

Sample data: there are multiple similar collection:
{
"_id" : NumberLong(301),
"telecom" : [
{
"countryCode" : {
"value" : "+1"
},
"extension" : [
{
"url" : "primary",
"value" : [
"true"
]
}
],
"modifiedValue" : {
"value" : "8887778888"
},
"system" : {
"value" : "phone"
},
"useCode" : {
"value" : "Home Phone"
},
"value" : {
"value" : "8887778888"
}
},
{
"extension" : [
{
"url" : "primary",
"value" : [
"true"
]
}
],
"modifiedValue" : {
"value" : "abc#test.com"
},
"system" : {
"value" : "email"
},
"useCode" : {
"value" : "work"
},
"value" : {
"value" : "abc#test.com"
}
}
]
}
Issue: I want to cont the collection where telecom.system.value = email and countryCode doesn't exist in the email part object. here I am attaching a script but I need one line query
var count = 0,i;
db.getCollection('practitioner').find({"telecom.system.value":"email"}).forEach(function(practitioner){
//print("updating : " +practitioner._id.valueOf())
telecom = practitioner.telecom.valueOf()
for(i= 0;i<telecom.length;i++){
if(telecom[i].system.value === 'email' && telecom[i].countryCode){
count+=1;
}
}
});
print(" Total count of the practitioner with country code in email object: "+count)
Above mention, the script is working fine and the output is as I expected. but the script is not optimised and I want to write in a single line query. Thanks in advance.
You can try aggregation method aggregate(),
Approach 1:
$match condition for countryCode should exists and system.value should be email
$filter to iterate loop of telecom array and check both condition, this will return expected elements
$size to get total element from above filter result
$group by null and count total
var result = await db.getCollection('practitioner').aggregate([
{
$match: {
telecom: {
$elemMatch: {
countryCode: { $exists: true },
"system.value": "email"
}
}
}
},
{
$project: {
count: {
$size: {
$filter: {
input: "$telecom",
cond: {
$and: [
{ $ne: [{ $type: "$$this.countryCode" }, "missing"] },
{ $eq: ["$$this.system.value", "email"] }
]
}
}
}
}
}
},
{
$group: {
_id: null,
count: { $sum: "$count" }
}
}
]);
print("Total count of the practitioner with country code in email object: "+result[0].count);
Playground
Approach 2:
$match condition for countryCode should exists and system.value should be email
$unwind deconstruct telecom array
$match to filter document using above conditions
$count to get total elements count
var result = await db.getCollection('practitioner').aggregate([
{
$match: {
telecom: {
$elemMatch: {
countryCode: { $exists: true },
"system.value": "email"
}
}
}
},
{ $unwind: "$telecom" },
{
$match: {
"telecom.countryCode": { $exists: true },
"telecom.system.value": "email"
}
},
{ $count: "count" }
]);
print("Total count of the practitioner with country code in email object: "+result[0].count);
Playground
I have not tested the performance but you can check and use as per your requirement.

In Mongo, how can I use $IN condition with values coming from another field?

Data :
{
_id :1111,
col1_array : ['a','b','c'],
col2_array : ['a','f','g']
}
I would like to find all documents where col2_array contains any value of col1_array. I tried using the $IN condition but failed to refer to other field content as an array. How can I do ?
db.collection.aggregate([
{ $unwind: "$col2_array" },
{
$project:
{
index: { $indexOfArray: ["$col1_array", "$col2_array"] },
col2_array: 1,
col1_array: 1,
_id: 1
}
},
{ $match: { index: { $gte: 0 } } },
{ $group: { _id: "$_id" } }
])
After that you have to find records of this particular _id
db.collection.find({_id:{$in:[result_of_above_query_ids]}})
I have finally resolved the problem using arrays intersections I have just discovered digging Mongo documentation :
db.getCollection('test').aggregate([
{$set : {
commonValues: { $setIntersection: [ "$col1_array", "$col2_array"]},
}},
{$match : {"commonValues" : {"$ne" : []}}}
])

Querying on an array of objects without using RHS as a reference in Mongo?

The Mongo Collection Looks like Below :
{
"_id" : ObjectId("5b693cbc032ee2fbb1d097f9"),
"name" : "PersonName1",
"email" : "dfgdfg#gmail.com",
"phone" : "46756456",
"address" : [
{
"Home" : "Home 1 person1"
},
{
"Work" : "Work1 person 1"
}
]
}
{
"_id" : ObjectId("5b6943b0032ee2fbb1d097fa"),
"name" : "PersoneName2",
"email" : "dfgdsfgdfg#gmail.com",
"phone" : "45645643",
"address" : [
{
"Home" : "Address of Home"
},
{
"Work" : "Address of Office"
}
]
}
Performing the below query on the above collection
db.subdocs.find({},{"address":{$elemMatch:{"Home":1}}});
The output of above query only returns the object ids:
{ "_id" : ObjectId("5b693cbc032ee2fbb1d097f9") },
{ "_id" : ObjectId("5b6943b0032ee2fbb1d097fa") }
How do I get it to display both the Home addresses from my collection?
You need to use $exists query element operator with $elemMatch projection to find whether the key is exists in the array or not
db.collection.find({},
{
address: {
$elemMatch: {
Home: {
$exists: true
}
}
}
})
Try it here
Your problem is about projection really doesn't match,
your query try find address.Home = 1 and you need items those contain address.Home (Home exists)
then, just perform query...
db.subdocs.find({},{"address": { $elemMatch: { "Home" : { $exists: true } } } );
or if you need Home contains something
db.subdocs.find({},{"address": { $elemMatch: { "Home" : { $regex: "person" } } } );
db.getCollection("subdocs").find({
address: {
$elemMatch: {
Home: {
$exists: true
}
}
}
}, {
'address.$.Home': 1
})

How to match and retrieve specific Sub-document value from Mongo

How can I search and retrieve only "Stats.item.id" from this collection who have greater than zero "Stats.item.p" value. I am also facing problem in unwinding this collection.
{
"_id" : "8643",
"Stats" : [
{
"date" : ISODate("2014-02-01"),
"Stats" : {
"item" : [
{
"id" : "4356"
},
{
"id" : "9963",
"p" : NumberInt(1)
}
]
}
}
]
}
{
"_id" : "8643",
{
"date" : ISODate("2014-02-01"),
"Stats" : {
"item" : [
{
"id" : "9963",
"p" : NumberInt(1)
}
}
This is the output I expect. Can anyone help me write this aggregation? oooooooooooooooooooooooooooooooooooooooooooooo ooooooooooooooooooooooooo oooooooooooooooooooo oooooooooooo oooooooo
Hope this aggregation query will work
db.collection.aggregate([
{$unwind:'$Stats'},
{$unwind:'$Stats.Stats'},
{$unwind:'$Stats.Stats.item'},
{$match:{
'Stats.Stats.item.p':{$gt:0}
}},
{$group:{
_id:{
date:'$Stats.date'
},
item:{$push:'$Stats.Stats.item'},
_ids:'$_id'
}},
{$group:{
_id:{_ids:'$_ids',
date:'$_id.date'},
Stats:{$push:{
item:'$item'
}},
}},
{$project:{
_id:'$_id._ids',
Stats:{
date:'$_id.date'
Stats:'$Stats'
}
}}
])
Use $elemMAtch for searching in the array.
db.getCollection('CollectionName').find({
"Stats": {
"$elemMatch": {
"Stats.item": {
"$elemMatch": {
"p": 1
}
}
}
}
})

Resources