MongoDB adding ObjectId to array of IDs - node.js

I have Poems schema which has a linked array of ObjectIds under field name 'communities':
{
_id: ObjectId("61659ef70e87b90018f7baa1"),
schemaName: 'Poem',
helps: [ ObjectId("5d15c609832d390c41ab6872") ],
communities:
[ ObjectId("5eafbabaf0be6f0017303eb3"),
ObjectId("5eba549a45bd9300170f6311") ],
}
I am trying to add a new ObjectId to the array using updateOne and $push:
db.poems.updateOne(
{title: "My stillness"},
{$push: {communities: {ObjectId: ('61f942b737bdc10018722539')}}}
)
While the new Id gets added, it is not in the correct format (see also attached image from MongoDB Compass for further clarity on the difference in format). How can I adjust my updateOne/$push method to add the ObjectId in the correct format? Thanks
{
_id: ObjectId("61659ef70e87b90018f7baa1"),
schemaName: 'Poem',
helps: [ ObjectId("5d15c609832d390c41ab6872") ],
communities:
[ ObjectId("5eafbabaf0be6f0017303eb3"),
ObjectId("5eba549a45bd9300170f6311"),
{ ObjectId: '61f942b737bdc10018722539' } ],
}

You are pushing key-value pair into the array.
ObjectId: ('61f942b737bdc10018722539')
Instead, it should be:
ObjectId('61f942b737bdc10018722539')
db.poems.updateOne(
{ title: "My stillness" },
{ $push: { communities: ObjectId('61f942b737bdc10018722539') } }
)
Sample Mongo Playground

Related

MongoDB: Access current value of document when adding element to array via $push

I have collection MyCollection which basically consists of its _id and a string called comment.
This collection should be bulk-updatable.
That's done like this:
for (const obj of inputObjects) {
bulkObjectsToWrite.push({
updateOne: {
filter: { _id: obj._id },
update: {
$set: {
comment: obj.comment
}
}
}
})
}
await MyCollection.bulkWrite(bulkObjectsToWrite)
So far so good.
However, now the requirement is, that a commentHistory should be added which should look like [{"oldValue": "oldValueOfComment", "newValue": "newValueOfComment"}, ...]
I know I need to use $push for adding a new object to the commentHistory array. But how do I access the comment of the document updated right now, i.e. its current value?
I've tried
$push: {
commentHistory: {
newValue: obj.comment,
oldValue: '$comment',
},
},
but to no avail. The string $comment is added hard-coded, instead of the field being accessed.
(Using Mongoose 5.12.10 and Mongo 4.4.18)
You need to use update with aggregate pipeline.
db.collection.update({
"key": 1
},
[
{
$set: {
"comment": "New",
"commentHistory": {
"$concatArrays": [ //concatenate existing history array with new array entry
"$commentHistory",
[
{
"newValue": "New",
"oldValue": "$comment" //referencing the existing value
}
]
]
}
}
}
])
Demo

Update nested object in array MongoDB

I need to find and update documents with category that corresponding to the query. Array could contain mo than one corresponding id.
Query:
{
"ids": ["61f1cda47018c60012b3dd01", "61f1cdb87018c60012b3dd07"],
"userId": "61eab3e57018c60012b3db3f"
}
I got collection with documents like:
`{
"_id":{"$oid":"61f1cdd07018c60012b3dd09"},
"expenses":[
{"category":"61eafc104b88e154caa58616","price":"1111.00"},
{"category":"61f1cdb87018c60012b3dd07","price":"2222.00"},
{"category":"61f1cda47018c60012b3dd01","price":"1241.00"},
{"category":"61f1cdb87018c60012b3dd07","price":"111.00"}
],
"userId":"61eab3e57018c60012b3db3f"
}`
my method:
async myMethod(ids: [string], userId: string) {
try {
const { ok } = await this.ExpensesModel.updateMany(
{"userId": userId, "expenses.category": { $in: ids }},
{$set: {"expenses.$.category": "newCategoryID"}}
);
return ok
} ........
I path array of ids ["61f1cda47018c60012b3dd01","61f1cdb87018c60012b3dd07","61f1cdb87018c60012b3dd07"] and userId, this code update only 1 category by document.
So can i made it with mongo build in methods? or i need to find matching document and update it it by my self and after that update or insert;
Update with arrayFilters
db.collection.update({
"expenses.category": {
$in: [
"61f1cda47018c60012b3dd01",
"61f1cdb87018c60012b3dd07"
]
}
},
{
$set: {
"expenses.$[elem].category": "61eab3e57018c60012b3db3f"
}
},
{
arrayFilters: [
{
"elem.category": {
$in: [
"61f1cda47018c60012b3dd01",
"61f1cdb87018c60012b3dd07"
]
}
}
]
})
mongoplayground

How can I write query in mongodb?

I have a collection of mongodb like this :
[{
"_id":"ObjectId(""51780fb5c9c41825e3e21fc4"")",
"name":"CS 101",
"students":[
{
"name":"raj",
"year":2016
},
{
"name":"rahul",
"year":2017
},
{
"name":"anil",
"year":2018
}
]
},
{
"_id":"ObjectId(""51780fb5c9c41825e3e21fs4"")",
"name":"CS 102",
"students":[
{
"name":"mukesh",
"year":2016
},
{
"name":"mohan",
"year":2017
},
{
"name":"mangal",
"year":2018
}
]
}
]
I've been looking for similar questions like this one: Mongo db - Querying nested array and objects but in that question they're looking for a specific element inside the "messages" object (in my case) for example. Same as in this other question: Query for a field in an object in an array with Mongo? where they're using $mapan d I don't think it fits my needs.
The documents to find have this structure:
[{
"_id":"ObjectId(""51780fb5c9c41825e3e21fc4"")",
"name":"CS 101",
"students":[
"raj","rahul","anil"
]
},
{
"_id":"ObjectId(""51780fb5c9c41825e3e21fs4"")",
"name":"CS 102",
"students":[
"mukesh","mohan","mangal"
]
}
]
how to solve this?
From the question and datasets, you are trying to return students with an array of student's name (string) instead of the array of student object.
Use $project to display students as students.name array.
db.collection.aggregate([
{
$project: {
"_id": "$_id",
"name": "$name",
"students": "$students.name"
}
}
])
Sample Solution 1 on Mongo Playground
OR
Use $set to replace the students field with students.name array.
db.collection.aggregate([
{
$set: {
"students": "$students.name"
}
}
])
Sample Solution 2 on Mongo Playground

How to return field based on other fields with mongoose

I have mongoose schema that looks something like this:
{
_id: someId,
name: 'mike',
keys: {
apiKey: 'fsddsfdsfdsffds',
secretKey: 'sddfsfdsfdsfdsds'
}
}
I don't want to send back to the front the keys of course, but I want some indication, like:
{
_id: someId,
name: 'mike',
hasKeys: true
}
There is built in way to create 'field' on the way based on other fields, or do I need every time fetch the whole document, check if keys is not empty and set object property based on that?
For Mongo version 4.2+ What you're looking for is called pipelined updates, it let's you use a (restricted) aggregate pipeline as your update allowing the usage of existing field values.
Here is a toy example with your data:
db.collection.updateOne(
{ _id: someId },
[
{
"$set": {
"hasKeys": {
$cond: [
{
$ifNull: [
"$keys",
false
]
},
true,
false
]
}
}
},
])
Mongo Playground
For older Mongo versions you have to do it in code.
If you don't want to update the actual document but just populate this field when you fetch it you can use the same aggregation to fetch the document
you can use $project in mongoose aggregation like this.
$project: { hasKeys: { $cond: [{ $eq: ['$keys', null] }, false, true]}}

Mongoose How to push to nested array with condition

Suppose I have the following schema:
{
userId: docId,
skills: [
{
_id: SkillId,
endorsers: [
{
userId: idOfUser
}
]
}
]
}
What I want is a user should not be able to endorse a specific skill in a document more than once. First should find a specific document using its docId, and inside that, a specific skill using skillId, and then check if its endorsers array is empty or a specific user not endorsed yet, then push.
What I tried so far:
{
"userId": req.params.userId,
"skills": {
"$elemMatch": {
"skillId": ObjectId(req.params.skillId),
"$or": [
{"endorsers": []},
{"endorsers.userId":{$ne: endorser._id}}
]
}
}
},
{
"$push": { "skills.$[outer].endorsers": endorserData }
},
{
"arrayFilters": [
{ "outer.skillId": ObjectId(req.params.skillId) }
]
}
But this is not working, and along update, I need the updated result.
You can use addToSet function of mongoose arrays to keep their elements unique. https://mongoosejs.com/docs/api.html#mongoosearray_MongooseArray-addToSet

Resources