How to solve Mongodb Duplicate Key Error on deletedAt - mongodb

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
}

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 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.

Updating All Nested Arrays in Mongo Object

My data structure is:
{
"_id": { "$oid" : "511D0A0EC075F3FF25000003" },
"progresses": [
{
"behavior": {
"behavior": {
"_id": "511d052f52fbf0fd25000002",
"disabled": false,
"name": "Unity Installed",
"key": "UnityInstalled",
"points": 1,
"timeout": 0
},
"key": "UnityNotInstalled",
"name": "Unity Not Installed",
"points": 1,
"timeout": 0,
"disabled": false,
"_id": { "$oid" : "511D056552FBF0FD25000003" }
},
"behaviorCount": 1,
"behaviorParameter": null,
"userId": null,
"modifiedAt": { "$date": 1360857614000.000000 },
"createdAt": { "$date": 1360857614000.000000 },
"behaviorType": "user"
},
{
"behavior": {
"behavior": {
"_id": "511cfac4955737a01f000001",
"disabled": false,
"name": "test",
"key": "tt",
"points": 1,
"timeout": 0
},
"name": "Unity Installed",
"key": "UnityInstalled",
"points": 1,
"timeout": 0,
"disabled": false,
"_id": { "$oid" : "511D052F52FBF0FD25000002" }
},
"behaviorCount": 3,
"behaviorParameter": null,
"userId": null,
"modifiedAt": { "$date": 1360858565000.000000 },
"createdAt": { "$date": 1360858553000.000000 },
"behaviorType": "user"
},
{
"behavior": {
"behavior": {
"_id": "511d052f52fbf0fd25000002",
"disabled": false,
"name": "Unity Installed",
"key": "UnityInstalled",
"points": 1,
"timeout": 0
},
"name": "Active User",
"key": "ActiveUser",
"points": 1,
"timeout": 0,
"disabled": false,
"_id": { "$oid" : "511D058E52FBF0FD25000004" }
},
"behaviorCount": 1,
"behaviorParameter": null,
"userId": null,
"modifiedAt": { "$date": 1360858565000.000000 },
"createdAt": { "$date": 1360858565000.000000 },
"behaviorType": "user"
},
{
"behavior": {
"behavior": {
"_id": "511d058e52fbf0fd25000004",
"disabled": false,
"name": "Active User",
"key": "ActiveUser",
"points": 1,
"timeout": 0
},
"name": "Invite Count",
"key": "InviteCount",
"points": 1,
"timeout": 0,
"disabled": false,
"_id": { "$oid" : "511D061752FBF0FD25000006" }
},
"behaviorCount": 1,
"behaviorParameter": null,
"userId": null,
"modifiedAt": { "$date": 1360858587000.000000 },
"createdAt": { "$date": 1360858587000.000000 },
"behaviorType": "user"
}
],
"trophyAchievements": [
],
"userId": "asfasd"
}
I want to update all progresses.behaviorCount to 1. How can i done that ?
You should use mongo's positional operator and dot notation.
In your case, I'd use smth like this:
db.test.update({}, {$set: {"progresses.$.behaviorCount": "testing"}}, { multi: true })
But, it won't update all fields in the nested array, just one at a time.
See similar problems:
MongoDB: Updating subdocument
Updating a sub-document in mongodb?
As a workaround, you can loop over nested array and update behaviorCount one at a time by index.
Hope that helps.
This script is the answer:
var i = 0;
db.users.find().forEach(function(doc) {
doc.progresses.forEach(function(progress) {
progress.behaviorCount = 1;
});
db.users.save(doc);
if (i % 10000 == 0) print(i);
i++;
});