I am trying to perform 2 operations in one findOneAndUpdate():
Update date in one field lastUpdatedTimestamp, set it to current date (this one works fine in my statement),
Update date in other field expiryTimestamp, by adding 1 day to $currentDate (I couldn't find a way to achieve it so I'm trying to $add 1 day to the the value read from the above field lastUpdatedTimestamp) - (I can't make this one work).
findOneAndUpdate(
{"_id":123},
{ $currentDate: {"lastUpdatedTimestamp":true}, $set: {"expiryTimestamp": {$add: ["$lastUpdatedTimestamp", 24*60*60000]}}}
)
Here's the error I'm receiving:
{ "ok" : 0.0, "errmsg" : "The dollar ($) prefixed field '$add' in 'expiryTimestamp.$add' is not valid for storage.", "code" : 52 }
Is it even possible? I'd appreciate your help.
You can use the setDate() method to set the "expiryTimestamp" value.
db.collection.updateOne(
{ "_id": 123 },
{ "$set": {
"lastUpdatedTimestamp": new Date(),
"expiryTimestamp": new Date().setDate(new Date().getDate() + 1)
}}
)
You don't need to use findOneAndUpdate unless you want to return the new or old document.
The marked answer is wrong in the sense that using new Date() will not use database timestamp which is important if your server and database hosted on different region and also count network time for sending data. To correctly do this, use $currentDate like this:
db.collection.findOneAndUpdate({_id: 123 }, {
$set: { /** update doc here **/ },
$currentDate: { lastUpdatedTimestamp: true}
});
Similarly using updateOne
db.collection.updateOne({_id: 123 }, {
$set: { /** update doc here **/ },
$currentDate: { lastUpdatedTimestamp: true}
});
Related
I need to find a way to auto-increment the "Bill_id" field by 1 , whenever I insert a new item to a nested array in a collection:
this is the structure of the nested document
I also found this demo on the official documentation :
https://docs.mongodb.com/v3.0/tutorial/create-an-auto-incrementing-field/
function getNextSequence(name) {
var ret = db.counters.findAndModify(
{
query: { _id: name },
update: { $inc: { seq: 1 } },
new: true
}
);
return ret.seq;
}
but I didn't know how to use the solution because it's proposing a JavaScript function that does all the work
However I am working with python script , and to be specific a REST API using flask
Write a similar function mentioned in the docs, in python. This is what I use.
def getLastUserId(self):
if len(list(self.find())) is not 0:
last_user = list(self.find({}).sort("user_id", -1).limit(1))
return last_user[0]["user_id"]
else:
return 0
This will return the "user_id" of the last added document. Just increment it by one, and do a simple insert for the new document.
I want to expire data in database ( its ok with expireAfterSeconds), but i want to use with collection.update>> data are always send data to database in real-time so TTL must be working on update data.. can i do that??
here is my code which i used for deleting a data from mongodb after specified time using ttl.
var time = "20";
MongoClient.connect(url, function(err, db) {
if (err) throw err;
var dbase = db.db("testing5");
var myobj = ({
"email" : scream_email,
"location_id" : location ,
"trend_tags" :trends ,
"language" : lang ,
"createdAt" : new Date(),
"emoji" : emoji,
"scream_link" : scream_path ,
"scream_type" : screamtype
});
dbase.collection("log_events").ensureIndex({ "email": 1 }, { expireAfterSeconds: time ,unique:true})
dbase.collection("log_events").insertOne(myobj, function(err, result) {
if (err) throw err;
resultant = result
console.log("data inserted and will be deleted approximately after 20 seconds");
db.close();
});
});
From the TTL Index manual:
To create a TTL index, use the db.collection.createIndex() method with the expireAfterSeconds option on a field whose value is either a date or an array that contains date values.
However your index creation uses email which I assume doesn't contain any date:
...ensureIndex({ "email": 1 }, { expireAfterSeconds: time ,unique:true})
Instead, you need to use the createdAt field to make the TTL index work, which I assumed contains the document's creation time:
...createIndex({ "createdAt": 1 }, { expireAfterSeconds: time })
Also, you don't want the unique: true constraint on the index. Otherwise, two documents inserted at exactly the same time will be disallowed by the database.
Please see Expire Data from Collections by Setting TTL for more examples.
Note that ensureIndex() is an old MongoDB idiom, and is deprecated since MongoDB 3.0. Use db.collection.createIndex() instead.
In MongoDB collection I have 3 objects. I need to update one variable (date type) in each object. The main task is to increment the date of the objects. For example: all objects have the same variable:
"Time1" : ISODate("2016-01-12T21:37:46.738Z")
My problem is to update the first object with the current date, manually I do it in this way:
$db.getCollection('my.data')({'_id':ObjectId("52e637fca92cf1ec6a73c1e8")}, {$currentDate: {Time1: true}})
The next is to increase the date of the second object by 1 day, I mean to update it with tomorrow date. I couldn't do it through the shell, because $inc doesn't work with Date type.
So, I am lost with javascript
I found how to get it with java script but I don't know how to collect all if this in one script.
var tomorrow = new Date();
tomorrow.setDate(today.getDate()+1);
Thank you for your help.
You could use the $set operator for the other fields, together the the $currentDate operator all within the update object:
var tomorrow = new Date();
tomorrow.setDate(tomorrow.getDate()+1);
var dayAfterTomorrow = new Date();
dayAfterTomorrow.setDate(dayAfterTomorrow.getDate()+2);
db.getCollection("my.data").update(
{ "_id": ObjectId("52e637fca92cf1ec6a73c1e8") },
{
"$currentDate": { "Time1": true },
"$set": {
"Time2": tomorrow,
"Time3": dayAfterTomorrow
}
}
)
Is there a quicker way to do this? From what I understand it cannot be done in a projection using the aggregation pipeline. Do I have to pre-calculate this? I basically want to emit part of the date (i.e. an hour) in a map function (for a map-reduce). I appreciate you taking the time to help me :-)
db.events.find().snapshot().forEach(
function (e) {
e.StartTime = new Date(e.start_time);
db.events.save(e);
}
)
The Bulk Operations API is the fastest "safe" way to do this:
var bulk = db.events.initializeOrderedBulkOp();
var count = 0;
db.events.find({ },{ "start_time": 1 }).snapshot().forEach(function(e) {
bulk.find({ "_id": e._id }).updateOne({
"$set": { "StartTime": new Date(e.start_time) }
});
count++;
if ( count % 1000 == 0 ) {
bulk.execute();
bulk = db.events.initializeOrderedBulkOp();
}
});
if ( count % 1000 != 0 )
bulk.execute();
That will only send and return from the server once per every 1000 documents read. So the decreased traffic there saves a lot of time, as does working with only the required fields.
If this is absolutely a "one off" operation that does not need to continue to happen in production, and if you are able to do so then you can always use db.eval(). But please read the documentation and warnings there as it is not a very good idea:
db.eval(function() {
db.events.find({ },{ "start_time": 1 }).snapshot().forEach(function(e) {
db.events.update(
{ "_id": e._id },
{ "$set": { "StartTime": new Date(e.start_time) } }
});
]);
But if you are looking for any other way to "convert" a field, there is presently no way for an update operation to refer to an existing value of a field and use it to update another, or even itself. There are exceptions such as $inc or $bit, but these have specific purposes.
I've created a Collection containing 1 million documents, and I'm trying to select 50000 of these records based on the ObjectID, and update one of the values (i'm working in Mongo shell, running on Ubuntu).
Is it possible to define a 50000 document range? It doesn't matter which documents are included in the 50000 range, I simply want to ringfence a definite number of records and run an update operation using the primary id so that I can measure the performance time.
The code I've tried to run doesn't work:
use Assignment
var _start = new Date()
db.FlightsDate.update({$set:{Airtime: 8888}}).limit(50000).hint({_id:1});
var _end = new Date();
print("Time to Bulk Update AirTime key for 50000 documents… " + ((_end _start)/1000));
...i'm gathering that MongoDB needs me to include a query in the command to specify which docs are to be updated (I now understand from reading other posts that .limit won't constrain the number of records than an .update writes to).
Please can anyone advise a method that'll enable me to define the number of records to be updated?
Grateful for advice.
R,
Jon
If you are simply looking for a "range" that covers 50,000 of the documents in the collection then your best approach is to query and find the "starting" and "ending" documents of your range first. Then apply that "range" specification to your update.
var start_id = db.FlightsDate.find({}).limit(1).toArray()[0]._id;
var end_id = db.FlightsDate.find({}).skip(49999).limit(1).toArray()[0]._id;
var _start = new Date();
db.FlightsDate.update(
{ "_id": { "$gte": start_id, "$lte": end_id } },
{ "$set"; { "Airtime": 8888 } },
{ "multi": true }
);
var _end = new Date();
( _end - _start )/1000;
If you then wanted the next 50,000 in an additional range then :
var start_id = db.FlightsDate.find(
{ "_id": { "$gt": end_id } }
).limit(1).toArray()[0]._id;
var end_id = db.FlightsDate.find(
{ "_id": { "$gt": end_id } }
).skip(49999).limit(1).toArray()[0]._id;
And do it all again.
The point is you need to know where to "start" and when to "end" within a range to limit your update to just 50,000 documents without any other criteria to do so.
Also note the usage of "multi" in the update method there. By default, .update() does not "update" any more than one document, essentially being the first match. So what you mean to do is update "all documents in the range" and that is why you need to apply "multi" here.