obj = {
date: 137097408891,
id: '1234',
value: 'value'
}
What I want to do it apply the value field to the object with the id, only if the date is newer then the current one saved. If no document with that ID is saved, just save this one.
I'm using node-mongodb-native. Is there a way to do this without first getting the document checking the date and saving it again?
Thanks
Given object o
db.collection.update( { id:o.id, date: { $lt:o.date } }, {$set : { o }}, {upsert:true} );
This is assuming there is a unique index on id.
Related
My document schema is as follows:
const CollectionSchema = mongoose.Schema({
ImageCategory:{type:String,required:true},
imgDetails: [
{
_id: false,
imageUrl:{type:String},
imageName:{type:String},
imageMimeType:{type:String},
}
],
Date: {
type: String,
default: `${year}-${month}-${day}`,
},
},{timestamps: true,})
So in the database for example one document has multiple images with a single image category. What I am trying to do is I want to delete an object from imgDetails array.
Let me explain my question more precisely: imgDetails is an array
Explanation: I want to loop in imgDetails and then find (where imgageUrl === req.body.imageUrl) if its match delete that whole object which have that req.body.imageUrl and then update the document.
Please guide me on how to write such a query. Regards
Demo - https://mongoplayground.net/p/qpl7lXbKAZE
Use $pull
The $pull operator removes from an existing array all instances of a value or values that match a specified condition.
db.collection.update(
{},
{ $pull: { "imgDetails": { imageUrl: "xyz" } } }
)
I am trying to create a historical record for updates to a document in Mongo DB via NodeJS. The document updates are only in one object within the document, so it seems like creating an array of historical values makes sense.
However, when I use the $push function with db.collection.update(), it only updates the array at the 0 index rather than add to the array.
Here is what I have:
{
_id: ID,
odds: {
spread: CURRENTSPREAD,
total: CURRENTTOTAL,
history: [
0: {
spread: PREVIOUSSPREAD1,
total: PREVIOUSTOTAL1,
date: DATEENTERED
}
]
}
}
Here is what I would like:
{
_id: ID,
odds: {
spread: CURRENTSPREAD,
total: CURRENTTOTAL,
history: [
0: {
spread: PREVIOUSSPREAD1,
total: PREVIOUSTOTAL1,
date: DATEENTERED1
},
1: {
spread: PREVIOUSSPREAD2,
total: PREVIOUSTOTAL2,
date: DATEENTERED2
},
...,
n: {
spread: PREVIOUSSPREAD-N,
total: PREVIOUSTOTAL-N,
date: DATEENTERED-N
}
]
}
}
There is no need to check whether the previous value exists before adding.
Here is my code:
var oddsHistoryUpdate = {
$push: {
'odds.history': {
spread: game.odds.spread,
total: game.odds.total,
date: Date.now()
}
}
}
db.collection('games').update({"_id": ID}, oddsHistoryUpdate).
.then(finish executing)
Why is it only pushing to the 0 index instead of adding to the array? How do I fix?
Bigga_HD's answer is the correct one regarding the $push operator. However, there may be an alternative solution that is more aligned to how MongoDB works under the hood.
A single document in MongoDB has a hard limit of 16MB, and if a document is frequently updated, it is possible that the array grows so large that it hits this limit.
Alternatively, you can just insert a new document into the collection instead of pushing the old document inside an array. The new & old documents can be differentiated by their insertion date. For example:
{
_id: ID,
name: <some identification>
insert_date: ISODate(...),
odds: {
spread: CURRENTSPREAD,
total: CURRENTTOTAL
}
}
You can then query the collection using a combination of e.g. its name and insert_date, sorted by its date descending, and limit by 1 to get the latest version:
db.collection.find({name: ...}).sort({insert_date: -1}).limit(1)
or remove the limit to find all versions:
db.collection.find({name: ...}).sort({insert_date: -1})
To support this query, you can create an index based on name and insert_date in descending order (see Create Indexes to Support Your Queries)
db.collection.createIndex({name: 1, insert_date: -1})
As a bonus, you can use a TTL index on the insert_date field to automatically delete old document versions.
$push
The $push operator appends a specified value to an array.
The $push operator has the form:
{ $push: { <field1>: <value1>, ... } }
If the field is absent in the document to update, $push adds the array field with the value as its element.
If the field is not an array, the operation will fail.
If the value is an array, $push appends the whole array as a single element. To add each element of the value separately, use the $each modifier with $push.
$each -Appends multiple values to the array field.
This should do the trick for you. Obviously, it's a very simplified example.
{ $push: { <field1>: { <modifier1>: <value1>, ... }, ... } }
let oddsHistoryUpdate = {
spread: game.odds.spread,
total: game.odds.total,
date: Date.now()
}
db.games.update(
{ _id: ID },
{ $push: { odds.history: oddsHistoryUpdate} }
)
I suggest try using Mongoose for your NodeJS - MongoDB interactions.
The answer was uncovered by dnickless.
In a previous call, I update the main odds object which I didn't realize was wiping out the history array.
Updating the previous call from
update($set: {odds: { spread: SPREAD, total: TOTAL }})
to
update($set: {"odds.spread": SPREAD, "odds.total": TOTAL})
and then making my $push call as written, all works fine.
In Mongo, is it possible to increase and get the result of the increment?
collection.update({id: doc_id}, {$inc: {view_count: 1}});
I tried to output the result of that statement (in node) and I got the following:
{ _id: 1,
_state: undefined,
_result: undefined,
_subscribers: [] }
You can use findAndModify. Add the new:true option.
According to the docs:
The findAndModify command modifies and returns a single document. By default, the returned document does not include the modifications made on the update. To return the document with the modifications made on the update, use the new option.
You could do the following:
db.collection.findAndModify(
query: {_id: doc_id},
update: { $inc: { view_count :1 } },
new: true,
)
If you canĀ“t find the findAndModify method to use on your collection,you can use the findOneAndUpdate method.
Here is how to use:
The following code finds the first document where name : R. Stiles and increments the score by 5:
const result = await db.grades.findOneAndUpdate(
{ "name" : "R. Stiles" }, //also you can search for id
{ $inc: { "points" : 5 } }
)
The code returns the original document before the update inside the "value" propety:
{ _id: 6319, name: "R. Stiles", "points" : 0,... } // result.value returns document before update, but in the db it changued
If you want get the document uploaded, you has to set "returnNewDocument" to true, so the operation would return the updated document instead.
I hope it works for you.
source: https://www.mongodb.com/docs/manual/reference/method/db.collection.findOneAndUpdate/
Hi I am facing a problem in updating an embedded object array using mongoose!
Here is the Schema:
var event = {
eTime : [String]
};
var schedule = {
events: [event]
};
var group = {
gName: {type:String},
sDate: { type: Date, default: Date.now },
schedules: [schedule]
};
MainSchema {
id : String,
groups : [group]
};
The thing which I want to do is that to update the array of eTime in events with an object of schedules. I am using this query
db.demoDb.update({
'id': 'MongoDb',
'groups':{
$elemMatch:{
'gName':'noSql'
}
}
},
{
$push:{
'groups':{
'schedules':{
'events':{
'eTime':'01-Marach-15'
}
}
}
}
}
)
but the schedules->events->eventTime is not updating with a value!!!
What wrong I am doing here?
My Main Scenario is to find the id(MongoDB) with associated gName and then update its schedules array of it.
My find query is working great but can not update the schedules... and events can be many
If I'm reading your schema correctly, the core part is an array containing an array containing an array containing an array of strings. I think you would do much better "inverting" the schema so each document represents an event. Metadata grouping multiple events can be duplicated into each event document. An example:
{
"event" : "cookie bake-off",
"gName" : "baking",
"sDate" : ISODate("2015-03-02T21:46:11.842Z")
}
The update that you are struggling with translates into an insertion of a new event document in the collection.
I have the following schema:
var sampleSchema = new Schema({
name: String,
dates: [{
date: Date,
duration: Number
}]
});
I'd need to filters the records according to the following rule: if one of dates is later than a given date date_begin, keep the record, otherwise, don't.
I have the impression that $gte or $lte are the function I need, but I can't find a way to use them correctly. I tried
sampleSchema.find({date_begin: {$gte: 'date'}});
or some variants of that, but I can't seem to be able to make it work. Anyone has an idea of how I am supposed to do this?
To do querying on elements inside arrays, $elemMatch is used :
SampleModel.find( { dates : { $elemMatch: { date : { $gte: 'DATE_VALUE' } } } } )
If you're using a single query condition, you can directly filter:
SampleModel.find( { 'dates.date': { $gte: 'DATE_VALUE' } } )