The date is not updated in MongoDB - node.js

When trying to update the date inside the MongoDB document, nothing is updated.
To update, I send a request to NodeJS like this:
collection.updateOne(
{ _id: ObjectId(...) },
{ $set: { 'field1.field2.0.date': new Date('2020-02-01T00:00:00Z') } },
callback
)
The task uses the npm package mongodb#2.3.26 and MongoDB 3.6.20.
I tried to send the '2020-02-01T00:00:00Z' as a value - it is not updated. I tried to update the database version - it didn't help. I tried to update the driver version - it didn't help.
It is interesting that such a request goes through Robo3T and updates the value correctly.
Could you please tell me how to update the date inside the document for MongoDB?
UPD: Structure of document
const document = {
field1: {
exp: 1,
field2: [
{
name: "test",
date: 2019-10-01 00:00:00.000Z
}
]
},
settings: {
sharedTill: 2022-10-01 00:00:00.000Z
},
updatedBy: 'Vadim Prokopchuk'
}
UPD2: Added Response from MongoDB
MongoDB returned data and does not return an error.

the syntax you're using isn't correct.
Refer the query below, it would work
collection.updateOne(
{ _id: ObjectId(...) , 'field1.field2.name':"test"},
{ $set: { 'field1.field2.$.date': new Date('2020-02-01T00:00:00Z') } },
callback
)
Here, we are finding the element of the array which matches our condition and then updating the date of that particular element of the array.

Related

How to remove object from array in Mongoose using updateMany?

I am trying to get an object removed from an array in MongoDB using Mongoose/Node and so far I have been unable to get it removed. I have read docs and SO posts to no luck. I'm hoping someone could give me specific advice on a solution not just a link to another post which is vaguely related
Mongo document example
{
managers: [{
userID: value,
// other fields and values
},
// Another object for another manager
]
}
Code I am trying to use
await Model.updateMany(
{'managers.userID': userID}, // This should be the query part
{$pullAll: {'managers': {'userID': userID}}} // This should be the update part
)
Using $pullAll you have to match the whole object.
Apart from the syntax is not correct in your query, check how in this example the id 1 is not removed but it is the id 2. That's because $pullAll expects to match the whole object. And this other example works removing both ids.
Then, to do your query you can use $pull and $in like this:
await Model.updateMany({
"managers.userID": userID
},
{
"$pull": {
"managers": {
"userID": {
"$in": userIDs
}
}
}
})
Example here
Note how $in expects an array. If you only want to remove based on one value you can avoid $in:
await Model.updateMany({
"managers.userID": userID
},
{
"$pull": {
"managers": {
"userID": userID
}
}
})
Example here

MongoDB Update & Aggregate Problem: Skipping over aggregation

I have two tables, one for messages to be logged and one that is for each member of the group. When a message is upvoted, I want to add an entry for the message and push each reaction on that message to an array.
Every time a reaction is added I want to update the member table to reflect the sum of all of the reaction.value fields.
This is the code I have written to do so. When this runs from a sandbox I made in VisualStudio using a MongoDB add on it runs fine, however when ran using my app, only the message document is added and without any error it appears to skip the aggregation to the member document.
Here is the code I am using to insert the documents to the database and to aggregate once the document is inserted:
await mongodb.collection("Messages").updateOne({ _id: reaction.message.id.toString()},
{
$set:{
authorid: reaction.message.author.id,
author: reaction.message.author.username
},
$push: {
reactions: {
reauth: reAuth,
reaction: reaction.emoji.name,
removed: false,
value: actualKarmaDB,
}
}
}, {safe: true, "upsert": true})
await mongodb.collection("Messages").aggregate([
{
$match: {
_id: reaction.message.id
}
},
{
$project: {
_id: "$authorid",
username: "$author",
messageKarma: {$sum: "$reactions.value"},
}
},
{ $merge: {
into: "Members",
on: "_id",
whenMatched: "replace",
whenNotMatched: "insert"
}
}])
Also here is a look at what the insertion into “Messages” looks like:
In this case the answer was due to mongoose not supporting merge for aggregation. Had to use $out.
Additionally this is a known issue with Mongoose Node.js, see here:
Mongodb node.js $out with aggregation only working if calling toArray()

In Mongo db I want to add an entry to a document. If the id already exists it should overwrite it, if not it should add it

I use Mongo DB and node.js. Thanks for any help :).
I want to do the following:
Search for a user in the db using the googleId.
Then if the user does not have a description field yet I want to create it. Within the description field, I want to have several objects that all have the coinId as an index.
If the coinId already exists it should overwrite the content of that particular object with the variables I pass. If it does not already exist it should add the new object to the description field.
The Mongo db document should look like this in the end. Note that 1027 or 123 are the values of the coinIds.
googleId: "PyovWaX8HERRACmeg4IzYCaMK833"
description:
1027:
_id: "ckpi7q8c60002qe9h0e4wgh3r"
coinId: 1027
description: "test1"
date: 2021-06-04T10:56:52.662+00:00
123:
_id: "woienfeiowfnaoewinfefneo"
coinId: 123
description: "test2"
date: 2021-06-04T10:56:52.662+00:00
I already tried the following:
const { result } = await db.collection('users').updateOne(
{ googleId },
{
$set: {
description: { [coinId]: { _id, coinId, description, date } },
},
},
{
returnOriginal: false,
}
);
The problem here is that the entry is always overwritten which I only want to happen if the coinId is the same.
I also tried to do it with $addToSet but then it never overwrites the object if the coinId's match.
How about findAndModify?
findAndModify
In your case, something like this:
db.collection('users').findAndModify({
query: { _id: googleId },
update: {
$setOnInsert: {
description: { [coinId]: { _id, coinId, description, date } },
}
},
new: true, // return new doc if one is upserted
upsert: true // insert the document if it does not exist
})
db.collection.findAndModify({
query: { _id: "some potentially existing id" },
update: {
$setOnInsert: { foo: "bar" }
},
new: true, // return new doc if one is upserted
upsert: true // insert the document if it does not exist
})

How to get the latest version of documents in MongoDB?

I have versioned documents stored in a MongoDb collection as follows:
{ _id: 'doc1-1', id: doc1, version: 1 ...},
{ _id: 'doc1-2', id: doc1, version: 2 ...},
{ _id: 'doc2-1', id: doc2, version: 1 ...}
I want to return all of the latest documents.
Example:
{ _id: 'doc1-2', id: doc1, version: 2 ...},
{ _id: 'doc2-1', id: doc2, version: 1 ...}
I know MongoDb includes operators such as Max and First but these do not seem to apply to subsets of documents within a query so I cannot get each document with a Max version of a unique id.
My goal is to return the full document and not project each field if possible. I'm currently using the MongoDb NPM package so that format of solution is preferred but any MongoDb solution is greatly appreciated.
EDIT: I am using AWS DocumentDb which uses MongoDb 4.0 so some newer Mongo features are not supported.
After some research the only solution I could identify was to make two separate calls to MongoDB.
First I used an aggregate call and grouped on id and max version.
const results = await collection.aggregate([
{
$sort: { version : -1 }
},
{
$group: {
_id: {
id: "$id"
},
version: { $max: "$version"}
}
}
]);
This returned the following response with the id and latest version.
{
_id: { id: "doc1" },
version: 2
},
{
_id: { id: "doc2" },
version: 1
}
I then mapped this response to get an array of the id appended with version to use as my query for getting each document.
const _ids = results.map(({ _id: { id }, version }) => (`${id}-${version}`));
const documents = await collection.find({
_id: { $in: _ids }
});
This returned all of the latest versions with the full document and was much more performant than filtering on server. However, I was not able to determine a method to get the complete document in one call so that solution would still be appreciated if possible.
An aggregation like this should work:
collection.aggregate([
{$sort: {id: 1, version: -1}},
{$group: {_id: '$id', doc: {$first: '$$ROOT'}},
{$replaceRoot: {newRoot: '$doc'}}
])
First bring your documents into a defined order with the latest version first, then group by id, keeping the first document via the $$ROOT variable, then unpack that again to retain only the wanted document.

Updating a nested subdocument's array - Mongoose

Currently I have the following structure for one of my documents
Company: {
Buildings: [{
Users: [ { _id: ObjectID, name: String, number: String } ]
}]
}
I'm trying to update the user's name and number and currently have tested and verified the following query in mongo:
db.companies.update(
{ "_id": companyID, "buildings._id": buildingID, "buildings.users._id": userID }
,
{ $set: { "buildings.$.users.0.name": "A new name for the user" } }
);
This query updates correctly however when I run the same exact query using mongoose
Company.findOneAndUpdate(
{ _id: companyID, "buildings._id": buildingID, "buildings.users._id": userID }
,
{ $set: { "buildings.$.users.0.name": newName }})
I get no error but the update is not performed.
Is the updating of a deep nested array not available on Mongoose?
Answer was found in an alternative answer to this question:
Answer: https://stackoverflow.com/a/28952991/1327815

Resources