I know this has been asked a number of times before but I can't seem to find the answer, How to update in nested array but objet in nested array without id???
const hasil = await Setting.update(
{ _id: Id, 'value.name': req.body.name },
{ "$set": { 'value.value': req.body.value } }
)
{
"_id" : 1234567,
"key" : "version",
"name" : "Collection Version",
"value" : [
{
"name" : "categories",
"value" : 7
},
{
"name" : "tag",
"value" : 1
},
{
"name" : "article",
"value" : 3
},
],
}
Related
I need to update a particular element of the nested array in mongoDB
My mongoDB data looks like below. I need to match the value accessid and name to update the status. The input content has
{"accessid" : 1627047023995, "name" : Name 09, "status" : 100 }
The input content may belong to any level
{
"_id" : ObjectId("60fac46ffcbf5287248460a9"),
"levelone" : [
{
"level" : [
{
"name" : "Name 01",
"status" : 5
},
{
"name" : "Name 02",
"status" : 0
},
{
"name" : "Name 03",
"status" : 0
}
],
"accessid" : "1627047023995"
},
{
"level" : [
{
"name" : "Name 09",
"status" : 5
},
{
"name" : "Name 15",
"status" : 3
}
],
"accessid" : "1627047023995"
}
],
"createdAt" : ISODate("2021-07-23T13:30:23.995Z")
}
I have tried to update the status, but it is updating only the first index value - name: Name 01 status. Please guide to resolve the issue.
collections.updateOne({
'levelone.level.accessid': accessid,
'levelone.level.name': name
}, { '$set': { 'levelone.$.level.status': status } }).exec();
you can use arrayFilters positional update,
query with $elemMatch to filter the main document
arrayFilters to define a variable for accessid and b for name
await collections.updateOne({
levelone: {
$elemMatch: {
accessid: accessid,
"level.name": name
}
}
},
{
$set: {
"levelone.$[a].level.$[b].status": status
}
},
{
arrayFilters: [
{ "a.accessid": accessid },
{ "b.name": name }
]
})
Playground
I am trying to get values by matching location ids. But I am getting error.in this locationId is an array like locationId[id1,id2] and location is an id.
Mongodb:
[err, assetsList] = await to(Assets.aggregate([
{
$match: {
"company" : new mongoose.Types.ObjectId(company)
// "auditAssetAvailability" : false
}
},
{
$lookup: {
from: "audits",
localField: "location",
foreignField: "locationId",
as: "asset_locations"
}
},
{
$unwind: '$asset_locations'
},
{
$match: {
"location" : { $in: [new mongoose.Types.ObjectId("asset_locations")] }
}
},
{
$project: {
"asset_locations":1,
"asset_name":1, "asset_code":1
}
},
]))
error:
message: "Argument passed in must be a single String of 12 bytes or a string of 24 hex characters"
it was working if I pass values like below:
{
$match: {
"location" : { $in: [new mongoose.Types.ObjectId("5f0968286fbe3f1278fb299f"),new mongoose.Types.ObjectId("5f09b8086fbe3f1278fb29a8")] }
}
},
Example:
Audit record:
{
"_id" : ObjectId("5fb3dcec0a3b9b4b44fb77c7"),
"locationId" : [
ObjectId("5f0968286fbe3f1278fb299f"),
ObjectId("5f09b8086fbe3f1278fb29a8")
],
"assetTypeId" : [
ObjectId("5f09683a6fbe3f1278fb29a0")
],
"auditUserId" : [
ObjectId("5f0c1a96bde0191914faa169")
],
"status" : true,
"startDate" : ISODate("2020-11-03T00:00:00.000Z"),
"endDate" : ISODate("2020-11-30T00:00:00.000Z"),
"company" : ObjectId("5f0964314a8580273c5ce687"),
"auditName" : "Q1 Audit",
"auditStatus" : ObjectId("5fb36cec93e1df254c4b97c3"),
"createdAt" : ISODate("2020-11-17T14:23:40.325Z"),
"updatedAt" : ISODate("2020-11-17T14:25:36.524Z")
}
asset record:
{
"_id" : ObjectId("5fb3e0620a3b9b4b44fb77d5"),
"discarded_date" : null,
"discordedNote" : null,
"company" : ObjectId("5f0964314a8580273c5ce687"),
"location" : ObjectId("5f09b8916fbe3f1278fb29a9"),
"statusCondition" : "stock_type"
}
Thank you in Advance.
I am new to mongo and NodeJS and have a use case where I want to get filtered results from multiple collection.
Advance apologies for the long post.
for ex:
collectionA
{
"_id" : "foo#gmail.com",
"name" : "Foo",
"location" : {
"coordinates" : [
-122.420170,
37.780080
],
"type" : "Point"
}
},
{
"_id" : "bar#gmail.com,
"name" : "Bar",
"location" : {
"coordinates" : [
-122.420060,
37.780180
],
"type" : "Point"
}
}
collectionB: Some attributes are not present for all the documents and hence optional
{
"_id" : "foo#gmail.com"
"AttributeA" : [
{
"name" : "AttA_Name",
"val" : "Coll_B_AttA_Val_Foo"
},
{
"name" : "AttA_Name1",
"val" : "Coll_B_AttA_Val_Foo"
}]
},
{
"_id" : "bar#gmail.com"
"AttributeA" : [
{
"name" : "AttA_Name",
"val" : "Coll_B_AttA_Val_Bar"
},
{
"name" : "AttA_Name2",
"val" : "Coll_B_AttA_Val_Bar"
}
],
"AttributeB" : [
{
"name" : "AttB_Name",
"val" : "Coll_B_AttB_Val_Bar"
}
]
}
CollectionC: Some attributes are not present for all the documents and hence optional
{
"_id" : "foo#gmail.com"
"AttributeA" : [
{
"name" : "Coll_C_AttA_Name",
"val" : "Coll_C_AttA_Val_Foo"
}]
},
{
"_id" : "bar#gmail.com"
"AttributeA" : [
{
"name" : "Coll_C_AttA_Name",
"val" : "Coll_C_AttA_Val_Bar"
}
],
"AttributeB" : [
{
"name" : "Coll_C_AttB_Name",
"val" : "Coll_C_AttB_Val_Bar"
}
]
}
I know Collection B and C schema looks the same but the purpose is different and they have to be different. DB design is not the question so I would appreciate if do not put all the focus on it.
Query:
Assume there is another user (Alan) with same attributes present as Bar that exist in the collection but is not living nearby the location of Bar.
The query I am trying to build on top of these is,
Find people living nearby from CollectionA
And Collection B, if AttributeA exist and have an element with name: AttA_Name
And in Collection C, if AttributeA exist and have an name: Coll_C_AttA_Name
In the above case I am expecting a result as
{
"_id" : "foo#gmail.com",
"name" : "Foo",
"location" : {
"coordinates" : [
-122.420170,
37.780080
],
"type" : "Point"
},
"collectionB_AttributeA" : [
{
"name" : "AttA_Name",
"val" : "Coll_B_AttA_Val_Foo"
},
{
"name" : "AttA_Name1",
"val" : "Coll_B_AttA_Val_Foo"
}]
,
"collectionC_AttributeA" : [
{
"name" : "Coll_C_AttA_Name",
"val" : "Coll_C_AttA_Val_Foo"
}]
},
{
"_id" : "bar#gmail.com,
"name" : "Bar",
"location" : {
"coordinates" : [
-122.420060,
37.780180
],
"type" : "Point"
},
"collectionB_AttributeA":[
{
"name" : "AttA_Name",
"val" : "Coll_B_AttA_Val_Bar"
},
{
"name" : "AttA_Name2",
"val" : "Coll_B_AttA_Val_Bar"
}
],
"collectionC_AttributeA":[
{
"name" : "Coll_C_AttA_Name",
"val" : "Coll_C_AttA_Val_Bar"
}
]
}
There is one way of doing is in parts:
query Collection A and get the nearby people
Loop through the result of 1 and find in CollectionB if they have AttributeA and an element with name AttA_Name and eliminate if they don't match.
Loop through the filtered results from 2 and find in CollectionC if they have AttributeA and and element with name Coll_C_AttA_Name and if they don't eliminate such documents.
Is there a way I can use aggregate to build this query as one? I tried reading and trying the aggregate but seems like my understanding is incomplete.
let result = await CollectionASchema.aggregate([
{
$geoNear: {
near: { type: "Point", coordinates: [ Number(long) , Number(lat) ] },
distanceField: "dist.calculated",
minDistance: 0,
maxDistance: radiusinmetres,
spherical: true
}
},
{
$lookup:
{
from: 'collectionB',
pipeline: [
{ $match : { $and: [{ AttributeA :{$exists: true}}, { [category]: { $elemMatch: { name: “AttA_Name” } } }] }},
{ $project: { AttributeA: 0 } }
],
as: "collectionB_AttributeA"
}
}
])
If you can explain if this is possible or let me know off this is the right approach that would be helpful.
This question already has answers here:
MongoDB Add an object to a nested object with condition [duplicate]
Updating a Nested Array with MongoDB
(2 answers)
Closed 4 years ago.
I have the format of:
{
"_id" : ObjectId("5af44cfbe2e96c58ec402efb"),
"username" : "egealpay2",
"email" : "egealpay2#gmail.com",
"fullName" : "ege",
"pnumber" : "",
"oneSignal" : "d427dcdf-7939-4ada-a035-be74e1e45091",
"friends" : [
{
"email" : "baransrc#gmail.com",
"status" : 2
}
],
"alarms" : [
{
"id" : "2",
"title" : "before",
"location" : "default",
"startTime" : "2018-05-16\t\t\t16:29",
"endTime" : "16:29\t\t\t17 - 05 - 2018",
"remindAt" : "17:29\t\t\t15 - 05 - 2018",
"privacy" : "0",
"userORJoinedAlarm" : "1",
"eventJoiners" : [
{
"email" : "ilkersadya#sabanciuniv.edu",
"status" : 1
},
{
"email" : "ilkercankayasss#sabanciuniv.edu",
"status" : 1
},
{
"email" : "ilkearcankaya#sabanciuniv.edu",
"status" : 1
},
{
"email" : "iaaalkercankaya#sabanciuniv.edu",
"status" : 1
}
],
"comments" : [ ]
}
]
}
i would like to set status: 2 of "email" : "ilkersadya#sabanciuniv.edu", its under"alarms:" , "eventJoiners" :which has an id of 2 as"id"`
I have tried using push with $ but couldnt manage to get this working and its been bugging me over 2 hours.
Update i had tried thanks to #Ashish:
dbo.collection("users").findOne( { email: userId } , function(errZer, addedZer) {
dbo.collection("users").findOneAndUpdate( {email: addedID, "alarms.id": eventIDGiv, alarms: { $elemMatch: { id: '2', eventJoiners: { $elemMatch: { email: addedID } } }} },
{ $set: { "alarms.$.eventJoiners.$.status": '2' } , function(err, added) {
got the error
(node:9334) UnhandledPromiseRejectionWarning: MongoError: Too many positional (i.e. '$') elements found in path 'alarms.$.eventJoiners.$.status'
Positional operator ($) can be used only for one level of nested arrays. In your case you have to specify conditions both for alarms and eventJoiners. To do that you can use $[< identifier >] syntax (which is available in MongoDB 3.6+):
db.collection.update(
{ _id: ObjectId("5af44cfbe2e96c58ec402efb") },
{ $set: { "alarms.$[elem1].eventJoiners.$[elem2].status": "2" } },
{ arrayFilters: [ { "elem1.id": "2" }, { "elem2.email": "ilkersadya#sabanciuniv.edu" } ]})
In this case identifiers elem1 and elem2 are used as placeholders for conditions specifed in arrayFilters section.
I have following offers collection
Here readBy contains the _id of the users...
Now I want to count the number of unRead offers for the userId = "5add82620d7f5b38240c63d4"
{
"_id" : ObjectId("5aeaab5ed6a9c97d0209260a"),
"expiresIn" : ISODate("2018-05-30T18:30:00.000Z"),
"name" : "Trip ",
"readBy" : [
ObjectId("5add82620d7f5b38240c63d4"),
ObjectId("5add82620d7f5b38240c63c6")
],
"__v" : 0
}
{
"_id" : ObjectId("5aeaab7dd6a9c97d0209260b"),
"expiresIn" : ISODate("2018-05-29T18:30:00.000Z"),
"name" : "Trip",
"readBy" : [ObjectId("5add82620d7f5b38240c63d4")],
"__v" : 0
}
{
"_id" : ObjectId("5aeae233d6a9c97d02092622"),
"expiresIn" : ISODate("2018-05-25T18:30:00.000Z"),
"name" : "two way off",
"readBy" : [],
}
{
"_id" : ObjectId("5aeae49643f10d284726069c"),
"expiresIn" : ISODate("2018-05-25T18:30:00.000Z"),
"name" : "two way off",
"readBy" : [],
}
{
"_id" : ObjectId("5aeae49743f10d284726069d"),
"expiresIn" : ISODate("2018-05-25T18:30:00.000Z"),
"name" : "two way off",
"readBy" : []
}
{
"_id" : ObjectId("5aeae49743f10d284726069e"),
"expiresIn" : ISODate("2018-05-25T18:30:00.000Z"),
"name" : "two way off",
"readBy" : []
}
so for the above collection my output should be
[{
numberOfUnreadOffers: 4
}]
because four of the collection does not have 5add82620d7f5b38240c63d4 in readBy array
You basically use $setIsSubset and $cond here:
var userId= "5add82620d7f5b38240c63d4";
Model.aggregate([
{ "$group": {
"_id": null,
"numberOfUnreadOffers": {
"$sum": {
"$cond": {
"if": {
"$setIsSubset": [[mongoose.Types.ObjectId(userId)], "$readBy"]
},
"then": 0,
"else": 1
}
}
}
}}
])
Of course you also need to "cast" using mongoose.Types.ObjectId from the "string" to a valid ObjectId value.
But really you get better performance from a simple count() instead:
Model.count({ "readBy": { "$ne": userId } })
So you really should not use .aggregate() for this at all.