M
M
matperez2018-02-08 15:17:12
MongoDB
matperez, 2018-02-08 15:17:12

How to implement document aging in MogonDB?

There is a collection of documents in mongo, which are, say, orders in an online store.

{"_id": ..., "status": "new", "expiring_at": 2018-02-04 23:40:40.493Z}

Each order, in the absence of payment, must go rotten after a certain time. When rotten, it needs to set the appropriate status (expired) and make a log entry about it. It is acceptable to mark orders as rotten a little later than specified in its properties, but never before.
How to implement it correctly?
My thoughts:
1. There are ttl indexes, which, due to the background process, allow you to set the lifetime of records, but I do not need to delete them, only change the status. In addition, there will be nothing to write to the log.
2. Every time you access a record, you don't want to check whether its lifetime has expired (that is, make the status a calculated value from the current time and order properties).
3. Use optimistic locking. When writing data, try to update the document with a given version, periodically search for and mark obsolete records using findAndUpdate($set status, $inc vesion, new true). Here confuses that it is operation over one record. Just update(), which can update documents in batches, does not report exactly which documents it updated at the output.
// upd if the logs are stored in the database in the same collection, then by the third option, in addition to increasing the version and changing the status, you can also do $push in the field with logs. this will allow you to score on single updates through findAndUpdate and just use update. + optimistic lock.
// upd 2
still stopped on a background process and optimistic lock
if err := col.Find(query).All(items); err != nil {
    return fmt.Errorf("unable to search expired orders: %s", err)
  }

  for _, item := range *items {
    if err := item.Expire(); err != nil {
      return fmt.Errorf("unable to mark the order as expired: %s", err)
    }
    item.Version++
    if err := col.Update(bson.M{"_id": item.ID, "version": item.Version - 1}, &item); err != nil {
      return fmt.Errorf("unable to store expired order: %s. possible a concurrent access issue", err)
    }
  }
  return nil

Since each entity is saved separately, there is no problem with finding out their final state.

Answer the question

In order to leave comments, you need to log in

1 answer(s)
R
RidgeA, 2018-02-08
@matperez

"expiration" - well, you need to come up with such a word
On the topic - there is still an option - an independent background cron / demon to do what you need.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question