Upserting Documents

296 views
Skip to first unread message

Benjamin

unread,
Mar 18, 2013, 3:21:25 PM3/18/13
to rav...@googlegroups.com
I am trying to execute an upsert in the Database.  I originally thought I may be able to pull this off using the Patch ability, but it seems that patch requires the document to already exist in the Database.

What I am trying to accomplish is to have two different processes each update a different property that may or may not exist yet.

TestClass
{
string Id{get; set;}
Guid OtherValue{get; set;}
int A {get; set;}
int B {get; set;}
}


Process one I want to increment A.
Process two I want to increment B.

The order in which this occurs is not guaranteed.  There will be high volume of traffic and I am not sure that a transaction scope using:

var doc = session.Load<TestClass>("docs/id");
if(doc == null)
{
  // insert
}
else
{
  // update
}

Is there an accepted way of accomplishing this?  Even better would to have the ability to upsert based on a query that wouldn't necessitate knowing the Id, but rather a value "OtherValue"

Cheers,

Ben

Khalid Abuhakmeh

unread,
Mar 18, 2013, 3:31:46 PM3/18/13
to rav...@googlegroups.com
This might be a naive solution, but why not have process one create the document and then process two update the document?

Benjamin

unread,
Mar 18, 2013, 4:18:55 PM3/18/13
to rav...@googlegroups.com
I can not guarantee the order that each process needs to upsert. I could, in each process, check to see if the document exists and then create it if necessary, but it is very likely that while the first process is checking if the document exists, the second process also checks for the existence before the first process creates the document.  If that is the case, they will both issue a "Put" and I will have data loss.

Kijana Woodard

unread,
Mar 18, 2013, 4:22:58 PM3/18/13
to rav...@googlegroups.com
Your code implies you always know the id up front.

Is it a full replacement (PUT)? 
If so, set the id and session.Store(doc);

Chris Marisic

unread,
Mar 18, 2013, 4:29:06 PM3/18/13
to rav...@googlegroups.com
If you opt into optimistic concurrency and you do

Store( { id:users/5 } )

and a 2nd thread has already created users/5, it should result in a concurrency exception that you can catch and retry your action.

If you rely on optimistic concurrency for insertion only when load(id) returns null, in your else block you should be able to rely on the patch commands to increment values in the document.


One thing to note with your statement: " Even better would to have the ability to upsert based on a query that wouldn't necessitate knowing the Id, but rather a value "OtherValue""

This will make your scenario greatly more complicated. You will not be able to call load(id) and instead will have to rely on query for checking existence. Since query is BASE, this raises likelihood of having to retry for trying to insert documents that were already created. You could however rely on patch and the OtherValue as a query parameter after the documents exist.

Chris Marisic

unread,
Mar 18, 2013, 4:31:58 PM3/18/13
to rav...@googlegroups.com
Giving some pseudo code, it'd probably look like:

try
{

var doc = session.Load<TestClass>("docs/id");
if(doc == null)
{
session.Advanced.UseOptimisticCurrency = true;
session.Store(new doc { id: "docs/id" }
session.SaveChanges()
  // insert
}
else
{
patch(session, ------ )
}
}
catch(ConcurrencyException)
{
patch(session, ----- )
}
Reply all
Reply to author
Forward
0 new messages