MongoDB sort by multiple fields on boolean type - mongodb

First of all i need "isFavourite": true then "isReadByPro": false and then updatedAt:-1.
I tried below way but not working.
{ $sort: { updatedAt: -1 } },
{ $sort: { isReadByPro: 1 } },
{ $sort: { isFavourite: -1 } },
[
{
"_id": "628c8378c92d4b969cf4b53b",
"post": {
"title": "project 94608"
},
"isFavourite": true,
"isReadByPro": true,
"updatedAt": "2022-06-06T10:34:05.776Z"
},
{
"_id": "628f507192034120c7fc261a",
"post": {
"title": "your payment test 1"
},
"isFavourite": true,
"isReadByPro": true,
"updatedAt": "2022-05-27T10:39:16.493Z"
},
{
"_id": "628f50a792034120c7fc2681",
"post": {
"title": "your payment test 3"
},
"isFavourite": true,
"isReadByPro": true,
"updatedAt": "2022-05-27T08:42:48.403Z"
},
{
"_id": "628c76840ffe2cd088654d50",
"post": {
"title": "showcase 1"
},
"isFavourite": false,
"isReadByPro": true,
"updatedAt": "2022-05-24T06:10:38.364Z"
},
{
"_id": "628c780a0ffe2cd088654e21",
"post": {
"title": "project 1 test"
},
"isFavourite": false,
"isReadByPro": true,
"updatedAt": "2022-05-27T06:30:54.058Z"
},
{
"_id": "628c79cb5b4b0ee6020482df",
"post": {
"title": "project 2 test"
},
"isFavourite": false,
"isReadByPro": true,
"updatedAt": "2022-05-27T06:30:54.058Z"
}
]

In order to sort by multiple fields, they should be on the same sorting object. The order of them is according to priority. This data is sorted first by isFavourite, then, all the documents with the same isFavourite value will be sorted between them by isReadByPro and so on.
{ $sort: {isFavourite: -1, isReadByPro: 1, updatedAt: -1} }

Related

Mongo DB query nested filter

I have this Mongo DB document structure...
{
"_id": {
"$oid": "63b6e12d650c56ca2e720c86"
},
"userName": "Harshit Gupta ",
"email": "harshitguptapositive#gmail.com",
"password": "$2b$10$Ys0AfxbtQKX3XytM1n85dO0dUL2bFAMQiD3w5nSw6zFmda4W4yRn6",
"tasks": [
{
"habbitName": "Jogging",
"Description": "defended",
"Sunday": false,
"Monday": true,
"Tuesday": false,
"Wednesday": true,
"Thursday": false,
"Friday": true,
"Saturday": false,
"Month": [
{
"date": 0,
"done": false,
"_id": {
"$oid": "63b6e14c650c56ca2e720c8d"
}
},
{
"date": 1,
"done": false,
"_id": {
"$oid": "63b6e14c650c56ca2e720c8e"
}
},
{
"date": 2,
"done": false,
"_id": {
"$oid": "63b6e14c650c56ca2e720c8f"
}
},
{
"date": 3,
"done": false,
"_id": {
"$oid": "63b6e14c650c56ca2e720c90"
}
},
{
"date": 4,
"done": false,
"_id": {
"$oid": "63b6e14c650c56ca2e720c91"
}
},
{
"date": 5,
"done": false,
"_id": {
"$oid": "63b6e14c650c56ca2e720c92"
}
},
{
"date": 6,
"done": false,
"_id": {
"$oid": "63b6e14c650c56ca2e720c93"
}
},
{
"date": 7,
"done": false,
"_id": {
"$oid": "63b6e14c650c56ca2e720c94"
}
},
{
"date": 8,
"done": false,
"_id": {
"$oid": "63b6e14c650c56ca2e720c95"
}
},
{
"date": 9,
"done": false,
"_id": {
"$oid": "63b6e14c650c56ca2e720c96"
}
},
{
"date": 10,
"done": false,
"_id": {
"$oid": "63b6e14c650c56ca2e720c97"
}
},
{
"date": 11,
"done": false,
"_id": {
"$oid": "63b6e14c650c56ca2e720c98"
}
},
{
"date": 12,
"done": false,
"_id": {
"$oid": "63b6e14c650c56ca2e720c99"
}
},
{
"date": 13,
"done": false,
"_id": {
"$oid": "63b6e14c650c56ca2e720c9a"
}
},
{
"date": 14,
"done": false,
"_id": {
"$oid": "63b6e14c650c56ca2e720c9b"
}
},
{
"date": 15,
"done": false,
"_id": {
"$oid": "63b6e14c650c56ca2e720c9c"
}
},
{
"date": 16,
"done": false,
"_id": {
"$oid": "63b6e14c650c56ca2e720c9d"
}
},
{
"date": 17,
"done": false,
"_id": {
"$oid": "63b6e14c650c56ca2e720c9e"
}
},
{
"date": 18,
"done": false,
"_id": {
"$oid": "63b6e14c650c56ca2e720c9f"
}
},
{
"date": 19,
"done": false,
"_id": {
"$oid": "63b6e14c650c56ca2e720ca0"
}
},
{
"date": 20,
"done": false,
"_id": {
"$oid": "63b6e14c650c56ca2e720ca1"
}
},
{
"date": 21,
"done": false,
"_id": {
"$oid": "63b6e14c650c56ca2e720ca2"
}
},
{
"date": 22,
"done": false,
"_id": {
"$oid": "63b6e14c650c56ca2e720ca3"
}
},
{
"date": 23,
"done": false,
"_id": {
"$oid": "63b6e14c650c56ca2e720ca4"
}
},
{
"date": 24,
"done": false,
"_id": {
"$oid": "63b6e14c650c56ca2e720ca5"
}
},
{
"date": 25,
"done": false,
"_id": {
"$oid": "63b6e14c650c56ca2e720ca6"
}
},
{
"date": 26,
"done": false,
"_id": {
"$oid": "63b6e14c650c56ca2e720ca7"
}
},
{
"date": 27,
"done": false,
"_id": {
"$oid": "63b6e14c650c56ca2e720ca8"
}
},
{
"date": 28,
"done": false,
"_id": {
"$oid": "63b6e14c650c56ca2e720ca9"
}
},
{
"date": 29,
"done": false,
"_id": {
"$oid": "63b6e14c650c56ca2e720caa"
}
},
{
"date": 30,
"done": false,
"_id": {
"$oid": "63b6e14c650c56ca2e720cab"
}
}
],
"timeRemind": "23:12",
"_id": {
"$oid": "63b6e14c650c56ca2e720c8c"
},
"createdAt": {
"$date": {
"$numberLong": "1672929612245"
}
},
"updatedAt": {
"$date": {
"$numberLong": "1672929612245"
}
}
}
}
],
"createdAt": {
"$date": {
"$numberLong": "1672929581689"
}
},
"updatedAt": {
"$date": {
"$numberLong": "1672939914562"
}
},
"__v": 2
}
I want to first select user id then specific the task id and the document which gets selected then
I want to update specific date of the month field can you please suggest the specific query..
first select select user by user id then a task by task id then in Month field i want to update a n element(done attribute to true) whose date is 4.
I tried to apply the following operation.
let doc = await User.findOneAndUpdate({
_id: req.user.id
}
,{
"tasks.$[task].Month.$[dateIndex].done": true
},{
arrayFilters:[ {"dateIndex.date" : 4} ,{"task.id":req.params.taskId}]
}
);
The positional parameter $ only matches the first element of the top-most array.
To update within an object in an array nested in another array, use arrayFilters and the $[] positional filter to refer into the nested arrays, like:
User.findOneAndUpdate({
_id: mongoose.Types.ObjectId(req.user.id),
"tasks._id": mongoose.Types.ObjectId(req.params.taskId)
},
{$set: {"tasks.$.Month.$[m].done": true}},
{
arrayFilters: [{"m.date": dateIndice}]
})
Playground

MongoDB $pull failing in different ways intermittently

I tried everything. update, updateMany, findOndAndUpdate, findByIdAndUpdate. I want to delete the object that matches the notification id.
indifferent approach it returns me the object, sometimes returns "mongodb cannot apply $pull to a non-array value"
and sometimes "mongodb matchedCount: 1 but modify 0".
This is one of the examples I tried
const userNotifications = await UserModel.findOneAndUpdate({_id: teacherUpdate.userId}, {
$pull: { notifications: {_id: notificationId} }
})
My DB:
{
"_id": "46df7324d6760d",
"username": "teacher",
"image": null,
"firstname": "Teacher",
"lastname": "Killer",
"skills": null,
"teacher": {
"teacherId": "046e2734d6260dc6"
},
"student": null,
"email": "teacher#gmail.com",
"activeSession": false,
"__v": 1,
"notifications": [
{
"type": "Lesson request",
"content": {
"date": "8.25",
"time": "10",
"status": "Pending",
"studentId": "d03d3c6d0085",
"teacherId": "2732d6286dc6"
},
"_id": "f9659d128c297f85",
"__v": 0
},
{
"type": "Lesson request",
"content": {
"date": "8.26",
"time": "08",
"status": "Pending",
"studentId": "8b4d3d3f8f3485",
"teacherId": "6e273246286d9c6"
},
"_id": "9659d1128c8b",
"__v": 0
}
]
},
Try this.
UserModel.update(
{ '_id': teacherUpdate.userId },
{ $pull: { notifications: { _id: notificationId } } },
false, // Upsert
true, // Multi
);
Edit
this should work
let updatedUser = await UserModel.findOneAndUpdate({ '_id': teacherUpdate.userId }, { $pull: { notifications: { _id: notificationId } } }, {
new: true
});

How to sum values using unwind in MongoDB with Spring Data

When using unwind("items") each item produces a duplicate line. This leads to revenue being counted as many times as there are items.
Example: Someone buys 1 item of A and 1 item of B, resulting in a cummulative value of 10. Unwind now inserts a row for each item, leading to a sum(cummulative) of 20.
I tried grouping the elements directly after unwind but have not managed to get it to work properly.
How can I sum each array element without duplication every other value?
I have this data structure
{
"_id": {
"$binary": "VEE6CsjHPvjzS2JYso7mnQ==",
"$type": "3"
},
"sequentialId": {
"$numberLong": "1"
},
"date": "2022-02-04",
"invoiceTotal": {
"$numberDecimal": "9.85"
},
"vatTotal": {
"$numberDecimal": "0"
},
"vatPercentage": {
"$numberDecimal": "19.00"
},
"invoiceNumber": "1111111",
"type": "ELEKTRONISCH",
"aktivkonto": 2800,
"passivkonto": 5200,
"buyerEmail": "",
"username": "",
"shop": "",
"externalId": "",
"shipped": false,
"actualShippingCost": {
"$numberDecimal": "1"
},
"filename": "",
"isReported": false,
"deliveryCostTotal": {
"$numberDecimal": "4.35"
},
"items": [
{
"lineItemId": "",
"amount": "1",
"sku": "A123123",
"title": "",
"priceTotal": {
"$numberDecimal": "4.50"
},
"vatTotal": {
"$numberDecimal": "0"
},
"hardwareCostPerPiece": {
"$numberDecimal": "0.22"
},
"hardwareCostTotal": {
"$numberDecimal": "0.22"
}
},
{
"lineItemId": "",
"amount": "1",
"sku": "B212312",
"title": "",
"priceTotal": {
"$numberDecimal": "1.00"
},
"vatTotal": {
"$numberDecimal": "0"
},
"hardwareCostPerPiece": {
"$numberDecimal": "0.22"
},
"hardwareCostTotal": {
"$numberDecimal": "0.22"
}
}
],
"packagingCost": {
"$numberDecimal": "0.15"
},
"hasInvoiceSent": false,
"tenant": "you!",
"createdAt": {
"$date": "2022-02-04T15:23:40.716Z"
},
"modifiedAt": {
"$date": "2022-02-04T15:23:40.716Z"
},
"_class": "_.RevenueEntity"
}
and this query
fun sumAllByWeeklyAndTenant(tenant: String): Flux<DashboardRevenue> {
val aggregation = newAggregation(
match(findByTenant(tenant)),
unwind("items"),
group("invoiceNumber")
.sum("items.hardwareCostTotal").`as`("hardwareCostTotal"),
project()
.andExpression("year(createdAt)").`as`("year")
.andExpression("week(createdAt)").`as`("week")
.andInclude(bind("hardwareCostTotal", "items.hardwareCostTotal"))
.andInclude(
"invoiceTotal",
"vatTotal",
"actualShippingCost",
"packagingCost",
"marketplaceFeesTotal",
"tenant"
),
group("year", "week", "tenant")
.sum("invoiceTotal").`as`("umsatz")
.sum("actualShippingCost").`as`("portokosten")
.sum("packagingCost").`as`("verpackung")
.sum("marketplaceFeesTotal").`as`("marketplaceFees")
.sum("hardwareCostTotal").`as`("hardwareCost")
.sum("vatTotal").`as`("vatTotal")
.count().`as`("numberOfInvoices"),
sort(Sort.Direction.DESC, "year", "week"),
limit(8),
sort(Sort.Direction.ASC, "year", "week")
)
return reactiveMongoTemplate
.aggregate(aggregation, "revenue", DashboardRevenue::class.java)
.toFlux()
}
Using the data above the query results in
[
{
"_id": {
"year": 2022,
"month": 2,
"week": 0,
"tenant": "einsupershop"
},
"umsatz": 19.70,
"portokosten": 2,
"verpackung": 0.30,
"marketplaceFees": 3.42,
"hardwareCost": 0.22,
"vatTotal": 0,
"numberOfInvoices": 2
}
]
Where the expected value is "invoiceTotal": { "$numberDecimal": "9.85" }

How to solve Mongodb Duplicate Key Error on deletedAt

Using mongoose-delete https://www.npmjs.com/package/mongoose-delete
I am gettings this error
E11000 duplicate key error index: hose_api.takeoffs.$horse_1_competition_1_event_1_deletedAt_1 dup key: { : ObjectId('5dd5dcb0f1dbcd08d0dda8ca'), : ObjectId('5f89f86444a69c11583086dd'), : ObjectId('5f89ed7504266450e81ea5ef'), : new Date(1602881879322) }"}
Every time i try to soft delete the document.
This is the index that i am using:
{ "horse": 1, "competition": 1, "event": 1, "deletedAt": 1 }
document example:
{
"_id": {
"$oid": "5f8a086a414a1a5d941557e0"
},
"entry": 0,
"hasPass": false,
"pass": 3,
"order": 999999,
"deleted": true,
"competitor": {
"$oid": "5e5f1a9e020c37154079fc15"
},
"competition": {
"$oid": "5f89f86444a69c11583086dd"
},
"horse": {
"$oid": "5dd5dcb0f1dbcd08d0dda8ca"
},
"payment": "NONE",
"event": {
"$oid": "5f89ed7504266450e81ea5ef"
},
"owner": {
"$oid": "5e056556b3b6192584c1f7a2"
},
"updatedAt": {
"$date": "2020-10-16T20:57:59.322Z"
},
"createdAt": {
"$date": "2020-10-16T20:54:02.268Z"
},
"__v": 0,
"deletedAt": {
"$date": "2020-10-16T20:57:59.322Z"
},
"deletedBy": null
}

How to get ids of parents based on deeply nested sub document?

This question is in continuation with older question: Parent.save() not working when sub document / deeply nested document is modified
Say I have a document as below :
{
"apiCallCount": 1,
"_id": "5e0da052b4b3fe5188602e11",
"email": "abc#def.net",
"password": "123123",
"userName": "username",
"companyName": "companyName",
"apiKey": "apiKey",
"solutionType": "solutionType",
"parentCompany": "parentCompany",
"buildings": [
{
"gateways": [
{
"devices": [
{
"_id": "5e0da052b4b3fe5188602e15",
"serialNumber": "serialNumber 1",
"area": "area",
"connectionStatus": 0,
"gatewayKey": "gatewayKey",
"applicationNumber": 11,
"firmwareVersion": "firmwareVersion",
"needsAttention": true,
"verificationCode": "123456",
"patientRiskStatus": "patientRiskStatus",
"patientFirstName": "UPDATED!!!",
"patientLastName": "patientLastName",
"createdAt": "2020-01-02T07:48:34.287Z",
"updatedAt": "2020-01-02T07:48:34.287Z"
},
{
"_id": "5e0da052b4b3fe5188602e14",
"serialNumber": "serialNumber 2",
"area": "area",
"connectionStatus": 0,
"gatewayKey": "gatewayKey",
"applicationNumber": 22,
"firmwareVersion": "firmwareVersion",
"needsAttention": true,
"verificationCode": "987654",
"patientRiskStatus": "patientRiskStatus",
"patientFirstName": "patientFirstName",
"patientLastName": "patientLastName",
"createdAt": "2020-01-02T07:48:34.288Z",
"updatedAt": "2020-01-02T07:48:34.288Z"
}
],
"_id": "5e0da052b4b3fe5188602e13",
"gatewayName": "gatewayName 1",
"gatewayKey": "gatewayKey",
"suite": "suite",
"createdAt": "2020-01-02T07:48:34.288Z",
"updatedAt": "2020-01-02T07:48:34.288Z"
}
],
"_id": "5e0da052b4b3fe5188602e12",
"buildingName": "buildingName 1",
"address": "address",
"suite": "suite",
"floor": "floor",
"timeZone": "String",
"createdAt": "2020-01-02T07:48:34.288Z",
"updatedAt": "2020-01-02T07:48:34.288Z"
}
],
"createdAt": "2020-01-02T07:48:34.289Z",
"updatedAt": "2020-01-02T09:10:25.200Z",
"__v": 0
}
I am able to dig through document and able to get device sub document with "verificationCode": "123456"
Now I want to get gatewayID(one level up) and buildingID(two level up) for this device.
Currently I have a call like this :
I am trying to update parent doc based on deeply nested sub-document.
I get sub document by accountId and verification code like below.
and then need to update the parent.
In my sample below I Put hard-coded ids which i need to get run time.
if (newlySavedUser) {
try {
let result = await Account.findByIdAndUpdate(
accountId,
{
$set: {
"buildings.$[building].gateways.$[gateway].devices.$[device].patientFirstName": "userName",
"buildings.$[building].gateways.$[gateway].devices.$[device].patientLastName": "userName1"
}
},
{
arrayFilters: [
{ "building._id": ObjectId("5d254bb179584ebcbb68b712") }, /// <---- I want to get this buildingId
{ "gateway._id": ObjectId("5d254b64ba574040d9632ada") }, /// <---- I want to get this gatewayId
{ "device.verificationCode": "4144" } /// <-- based on this verificationCode
],
new: true
}
);
if (!result) return res.status(404);
console.log(result)
//res.send(result);
} catch (err) {
console.log(err);
res.status(500).send("Something went wrong");
}
}
Trying "tom slabbaert" solution for aggregate.
Account.aggregate([
{
$unwind: "$buildings"
},
{
$unwind: "$gateways"
},
{
$match: {
"buildings.gateways.devices.verificationCode": "4144"
}
},
{
$project: {
buildingID: "$buildings._id",
gatewayID: "$gateways._id",
}
}
]).exec((err, result)=>{
console.log("result", result)
if(err) throw err;
});
Your help is appreciated.
You can use this 3 level $unwind aggregation, and then match the document you want:
db.collection.aggregate([
{
$unwind: "$buildings"
},
{
$unwind: "$buildings.gateways"
},
{
$unwind: "$buildings.gateways.devices"
},
{
$match: {
"buildings._id": "5e0da052b4b3fe5188602e12",
"buildings.gateways._id": "5e0da052b4b3fe5188602e13",
"buildings.gateways.devices.verificationCode": "123456"
}
}
])
This will give you the following result:
[
{
"__v": 0,
"_id": "5e0da052b4b3fe5188602e11",
"apiCallCount": 1,
"apiKey": "apiKey",
"buildings": {
"_id": "5e0da052b4b3fe5188602e12",
"address": "address",
"buildingName": "buildingName 1",
"createdAt": "2020-01-02T07:48:34.288Z",
"floor": "floor",
"gateways": {
"_id": "5e0da052b4b3fe5188602e13",
"createdAt": "2020-01-02T07:48:34.288Z",
"devices": {
"_id": "5e0da052b4b3fe5188602e15",
"applicationNumber": 11,
"area": "area",
"connectionStatus": 0,
"createdAt": "2020-01-02T07:48:34.287Z",
"firmwareVersion": "firmwareVersion",
"gatewayKey": "gatewayKey",
"needsAttention": true,
"patientFirstName": "UPDATED!!!",
"patientLastName": "patientLastName",
"patientRiskStatus": "patientRiskStatus",
"serialNumber": "serialNumber 1",
"updatedAt": "2020-01-02T07:48:34.287Z",
"verificationCode": "123456"
},
"gatewayKey": "gatewayKey",
"gatewayName": "gatewayName 1",
"suite": "suite",
"updatedAt": "2020-01-02T07:48:34.288Z"
},
"suite": "suite",
"timeZone": "String",
"updatedAt": "2020-01-02T07:48:34.288Z"
},
"companyName": "companyName",
"createdAt": "2020-01-02T07:48:34.289Z",
"email": "abc#def.net",
"parentCompany": "parentCompany",
"password": "123123",
"solutionType": "solutionType",
"updatedAt": "2020-01-02T09:10:25.200Z",
"userName": "username"
}
]
Mongoplayground
A simple aggregation would suffice:
db.collection.aggregate([
{
$unwind: "$buildings"
},
{
$unwind: "$buildings.gateways"
},
{
$match: {
"buildings.
gateways.devices.verificationCode": "123456"
}
},
{
$project: {
buildingID: "$buildings._id",
gatewayID: "$gateways._id",
}
}
])
If its possible to get duplicates you can $group on buildingID to avoid that.