Upsert Add To Set Or Update if Exist

1,089 views
Skip to first unread message

Kader Belbina

unread,
May 16, 2011, 11:11:03 PM5/16/11
to mongodb-user
I am using the C# driver and intend to have on document for graphs
that looks like this:

{
id: someid
name: "somename"
datapoints: {
{ 06/20/10: Date, somecounter: somevalue }
{ 06/21/10: Date, somecounter: somevalue }
{ 06/22/10: Date, somecounter: somevalue }
}
}

I am trying to figure out either using the C# driver how to :
- increment somecounter if the array entry exists or
- add to set (create) the array entry if it does exist

I am attempting to use an upsert and only have one trip to the db.

Any advice? Hope this isn't too confusing.

Scott Hernandez

unread,
May 16, 2011, 11:14:27 PM5/16/11
to mongod...@googlegroups.com
It is best to create the datapoints ahead of time, and then just increment the counters when needed. That way you can decouple the two operations. Is that possible for you?


--
You received this message because you are subscribed to the Google Groups "mongodb-user" group.
To post to this group, send email to mongod...@googlegroups.com.
To unsubscribe from this group, send email to mongodb-user...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/mongodb-user?hl=en.


Kader Belbina

unread,
May 16, 2011, 11:19:23 PM5/16/11
to mongodb-user
The problem is I am trying to upsert the entire document it is not
guaranteed that a document with "somename" will exist and there can be
a very large number of new documents every day.

Here's what I've got

var query = Query.EQ("Name", nameWeAreLookingFor);

var update = Update.Set("age", age);

// need to add the graph data to the update

collection.Update(query, update, UpdateFlags.Upsert);

Scott Hernandez

unread,
May 16, 2011, 11:23:19 PM5/16/11
to mongod...@googlegroups.com
I think you will need a feature that doesn't exist yet for your current structure (https://jira.mongodb.org/browse/SERVER-340). If you post the structure of your document (and a sample), and what you are trying to do we may be able to help you adjust to something which will work.

Kader Belbina

unread,
May 16, 2011, 11:28:01 PM5/16/11
to mongodb-user
I posted the sample and what I am trying to do here.

You mean post something in more detail on the forum or post something
in more detail on the link provided?

Scott Hernandez

unread,
May 16, 2011, 11:35:12 PM5/16/11
to mongod...@googlegroups.com
I meant something here with more detail about the updates. What does this "// need to add the graph data to the update" mean in practice?

The sample you posted was generic and didn't seem specific to what you are really doing; it seem contrived.

What is the process for incrementing counters?

Kader Belbina

unread,
May 16, 2011, 11:42:53 PM5/16/11
to mongodb-user
Okay well its for a database that tracks poker hands. A document might
look something like this:

{
"Name": "Screenname",
"Site": 1,
"TotalHands": 4548,
"WinningsGraphData" :
{
{ Date: "06/20/11", Winnings: 864.32 },
{ Date: "06/21/11", Winnings: 554.32 },
{ Date: "06/22/11", Winnings: -332.45 },
{ Date: "06/28/11", Winnings: 164.32 }
}

So when I insert a new hand history I also need to update the graphs
data for that player. They may have never played a hand on that date
so it would be a new entry, or they may have so I need to increment
the winnings. In addition, when I update the graphs for that hand the
player may not even exist so the entire player is upserted.

Scott Hernandez

unread,
May 17, 2011, 12:06:40 AM5/17/11
to mongod...@googlegroups.com
Unfortunately I can't see a good way to do this (in a single update w/upsert) without something like $iset or without support for $set + $inc in the same array element; both of which are coming....

I would suggest that for now you do two updates, and make them dependent. You can do the first ($inc based on name + date), check the result and then do the second (if the $inc doesn't hit an existing doc).

Kader Belbina

unread,
May 17, 2011, 12:40:19 AM5/17/11
to mongodb-user
So when you say check the result you mean do a query.

1 - upsert non array fields
2 - Query to see if the date exists in the array.
3 - Upsert or add to set depending on step 2.

So this would be 3 database operations?

Thanks for the help,
I take it there are plans to implement a feature to make this possible
in 1 action. Any ETA?

Robert Stam

unread,
May 17, 2011, 1:24:51 PM5/17/11
to mongodb-user
I would do it this way:

1. Attempt to increment an existing Winnings entry
2. If that fails, attempt to add a new Winnings entry to an existing
user
3. If that fails, add a new user

This would be 1 database operation when adding new winnings for the
same day, 2 database operations when adding new winnings for a new day
to an existing user, and 3 database operations for a new user. That
means most of the time it would be 1 or 2 operations.

Here's a sample program I wrote to test that this really works:

http://www.pastie.org/1917357

You could cut this down to just 1 or 2 database operations if your
data model were slightly different:

{
Name : "Robert",
Site : 1,
TotalHands : 1234,
WinningsGraphData : {
Date20110517 : 100.00,
Date20110518 : 200.00
}
}

where we are using the dates as part of the names of the winnings
entries.

On May 17, 12:40 am, Kader Belbina <ka...@nitricburnstudios.com>
wrote:

Kader Belbina

unread,
May 20, 2011, 9:35:03 PM5/20/11
to mongodb-user
Awesome. Thanks for the help and the code sample.
Reply all
Reply to author
Forward
0 new messages