最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - MongoDB, conditional upserts or updates - Stack Overflow

programmeradmin3浏览0评论

When using MongoDB I'm currently doing a conditional upsert as a part of an aggregation process, on the form (simplified alot):

db.dbname.update({attr1 : value1, attr2 : value2},
                 {"$inc" : { avg : current_value, nr : 1}},
                 false (multi), true (upsert))

But I want to able to keep a maximum (and minimum) value as well, without having to retrieve the document. Something along the lines of:

db.dbname.update({ attr1 : value1, attr2 : value2},
                 {"$inc" : { avg : current_value, nr : 1},
                  "$setIfBigger" : { max : current_value}},
                 false (multi), true (upsert))

Is this possible in an efficient way?

My current, extremely inefficient, solution is that I check for a current aggregation document, and if it exists I update the values accordingly, and if it doesn't I create a new document. Example (again, simplified alot, but the essence is there):

var obj = db.dbname.findOne({attr1 : value1, attr2 : value2},{_id:1});
if (obj != null) {
   db.dbname.update({attr1 : value1, attr2 : value2},
                    {"$inc" : { avg : current_value, nr : 1},
                     "$set" : { max : (obj.max > current_value ? obj.max : current_value}},
                    false (multi), true (upsert));
} else {
   db.dbname.save({attr1 : value1, attr2 : value2, 
                   avg : current_value, nr : 1,
                   max : current_value});
}

The actual program is written in Java and uses the mongo-API, and the aggregation process is quite complex and uses composition techniques way beyond Javascript to communicate with other servers, ergo mapreduce is not an option. Finally the end result is quite a humongous set of simple values which I want to store in the most effecient way and also store precalculated averages, maximums and minimums of certain combinations.

One solution is creating unique function-objects in JS for every single update, which I believe is not an efficient way?

The main objective is to decrease the time taken to perform an aggregation of this type, bandwidth usage is secondary.

When using MongoDB I'm currently doing a conditional upsert as a part of an aggregation process, on the form (simplified alot):

db.dbname.update({attr1 : value1, attr2 : value2},
                 {"$inc" : { avg : current_value, nr : 1}},
                 false (multi), true (upsert))

But I want to able to keep a maximum (and minimum) value as well, without having to retrieve the document. Something along the lines of:

db.dbname.update({ attr1 : value1, attr2 : value2},
                 {"$inc" : { avg : current_value, nr : 1},
                  "$setIfBigger" : { max : current_value}},
                 false (multi), true (upsert))

Is this possible in an efficient way?

My current, extremely inefficient, solution is that I check for a current aggregation document, and if it exists I update the values accordingly, and if it doesn't I create a new document. Example (again, simplified alot, but the essence is there):

var obj = db.dbname.findOne({attr1 : value1, attr2 : value2},{_id:1});
if (obj != null) {
   db.dbname.update({attr1 : value1, attr2 : value2},
                    {"$inc" : { avg : current_value, nr : 1},
                     "$set" : { max : (obj.max > current_value ? obj.max : current_value}},
                    false (multi), true (upsert));
} else {
   db.dbname.save({attr1 : value1, attr2 : value2, 
                   avg : current_value, nr : 1,
                   max : current_value});
}

The actual program is written in Java and uses the mongo-API, and the aggregation process is quite complex and uses composition techniques way beyond Javascript to communicate with other servers, ergo mapreduce is not an option. Finally the end result is quite a humongous set of simple values which I want to store in the most effecient way and also store precalculated averages, maximums and minimums of certain combinations.

One solution is creating unique function-objects in JS for every single update, which I believe is not an efficient way?

The main objective is to decrease the time taken to perform an aggregation of this type, bandwidth usage is secondary.

Share Improve this question edited Sep 22, 2017 at 17:57 CommunityBot 11 silver badge asked Apr 4, 2011 at 14:39 flindebergflindeberg 5,0071 gold badge26 silver badges37 bronze badges
Add a comment  | 

2 Answers 2

Reset to default 15

This can now be done much more easily in the MongoDB 2.6 release which includes Insert and Update Improvements. Specifically there are new $min and $max operators that perform a conditional update depending on the relative size of the specified value and the current value of a field.

So for example this update:

db.scores.update( { _id: 1 }, { $max: { highScore: 950 } } )

would conditionally update the specified document if 950 is greater than the current value of highScore.

One solution is creating unique function-objects in JS for every single update, which I believe is not an efficient way?

May not work as you'd like it to:

https://jira.mongodb.org/browse/SERVER-458

Is this possible in an efficient way?

The issue you're facing is that you want MongoDB to perform an upsert with some more complex logic. So you want to leverage the document-level locking to effectively "trigger" multiple complex changes all at once.

You're not the first one to want this, unfortunately it's not available right now. There are several server bugs tied to this type of "more complex update behavior". You may want to watch / vote on a few of the following to check for progress.

$set only when inserting, add only when not existing, push and set at the same time, coordinate a "size" with $addToSet.

In particular, SERVER-458 seems closest to what you want.

发布评论

评论列表(0)

  1. 暂无评论