Upsert Array Issue

48 views
Skip to first unread message

Neal Kranes

unread,
Oct 25, 2012, 11:38:10 AM10/25/12
to mongodb...@googlegroups.com
I have a document that I want to Upsert an array into.  Here's the initial document:
{
    "_id" : "F_S_17460317_0",
    "featureid" : 17460317,
    "featuretype" : "S",
    "builddate" : ISODate("2012-10-16T13:28:00Z"),
    "lastediteddate" : ISODate("2012-05-31T07:23:37.963Z")
}

var query = MongoDB.Driver.Builders.Query.EQ("_id", "F_S_17460317_0");
var update = Update.AddToSet("unifiedassociations", 
    {
        "_id" : "A_C_345_S_17460317_0", 
        "associationid" : 82152889, 
        "parentkey" : null, 
        "containerid" : 345, 
        "containertype" : "C", 
        "featureid" : 17460317, 
        "featuretype" : "S", 
        "cachedate" : ISODate("2012-10-25T15:24:01.43Z") }
    );
_collection.FindAndModify(query, SortBy.Null, update, false, true);

This inserts the array properly, with one element added:
{
    "_id" : "F_S_17460317_0",
    "featureid" : 17460317,
    "featuretype" : "S",
    "builddate" : ISODate("2012-10-16T13:28:00Z"),
    "lastediteddate" : ISODate("2012-05-31T07:23:37.963Z"),
    "unifiedassociations" : 
    [
        { "_id" : "A_C_345_S_17460317_0", 
            "associationid" : 82152889, 
            "parentkey" : null, 
            "containerid" : 345, 
            "containertype" : "C", 
            "featureid" : 17460317, 
            "featuretype" : "S", 
            "cachedate" : ISODate("2012-10-25T15:24:01.43Z") 
        }
    ]
}

But when I change a field and re-run the query a new record is inserted, even though the _id's are the same:
{
    "_id" : "F_S_17460317_0",
    "featureid" : 17460317,
    "featuretype" : "S",
    "builddate" : ISODate("2012-10-16T13:28:00Z"),
    "lastediteddate" : ISODate("2012-05-31T07:23:37.963Z"),
    "unifiedassociations" : 
    [
        { "_id" : "A_C_345_S_17460317_0", 
            "associationid" : 82152889, 
            "parentkey" : null, 
            "containerid" : 345, 
            "containertype" : "C", 
            "featureid" : 17460317, 
            "featuretype" : "S", 
            "cachedate" : ISODate("2012-10-25T14:25:01.43Z") 
        },
        { "_id" : "A_C_345_S_17460317_0", 
            "associationid" : 82152889, 
            "parentkey" : null, 
            "containerid" : 345, 
            "containertype" : "C", 
            "featureid" : 17460317, 
            "featuretype" : "S", 
            "cachedate" : ISODate("2012-10-25T15:11:01.43Z") 
        }
    ]
}

I've tried a bunch of different calls, but I can't seem to get it to work.  I'm not even sure if this is possible.

Help.

Neal Kranes

unread,
Oct 25, 2012, 5:06:18 PM10/25/12
to mongodb...@googlegroups.com
I ended up putting a 2 phase Try Update / Else Insert logic:
// Try to update item first
var query = MongoDB.Driver.Builders.Query.And(
    MongoDB.Driver.Builders.Query.EQ("_id", "F_S_17460317_0"),
    MongoDB.Driver.Builders.Query.EQ("unifiedassociations._id", association._id)
);
var update = Update.Set("unifiedassociations", "[document, removed for brevity]");
var updateAttemptResult = _featureCollection.Update(query, update, SafeMode.True);

// If not, insert
if (updateAttemptResult.DocumentsAffected == 0)
{
    query = MongoDB.Driver.Builders.Query.EQ("_id", GetFeatureCacheKey(feature));
    update = Update.AddToSet("unifiedassociations", "[document, removed for brevity]");
    updateAttemptResult = _featureCollection.Update(query, update, SafeMode.True);
}

Is this my best bet?

I was hoping to get it done in 1 statement, but after reading a bit it seems that might not be possible.

Neal

Robert Stam

unread,
Oct 25, 2012, 10:45:01 PM10/25/12
to mongodb...@googlegroups.com
Your cachedate values are different, and that's enough for $addToSet to consider it a new element of the unifiedassociations array.

Neal Kranes

unread,
Oct 26, 2012, 7:11:19 AM10/26/12
to mongodb...@googlegroups.com
I figured.  Is there any way to Upsert the array element purely based on _id?  Is the way I've outlined pretty much the best method to perform the Upsert at this time?  Is there a better method?

Thanks!

Neal

Amith George

unread,
Nov 28, 2012, 10:18:38 AM11/28/12
to mongodb...@googlegroups.com
@Robert Stam, I meant to post a reply to the group, but it got sent to only you.
-------

> Your cachedate values are different, and that's enough for $addToSet to consider it a new element of the unifiedassociations array.

Does the C# version of AddToSet compare every single property? Or it does only compare the Id property? Or does it use the Equals()/GetHashCode() of the objects? I am using AddToSet as a means to add an object to the array only if it doesn't exist. Even if one or two no important properties change, the element should not be added if one with the same Id exists. And in my basic testing this seems to work. I don't have any duplicates. 


Robert Stam

unread,
Nov 28, 2012, 10:29:45 AM11/28/12
to mongodb...@googlegroups.com
The comparison is actually made at the server (so it definitely doesn't use Equals/GetHashCode).

The server compares the entire object to decide if it is already in the set or not.

If you want the decision to be based on a partial comparison of the objects you will have to do that in your application (and use Set instead of AddToSet to replace the entire set at once with the value of your client side modified set).
Reply all
Reply to author
Forward
0 new messages