AddToSet where sub document doesn't already exist

908 views
Skip to first unread message

Sam Martin

unread,
Apr 29, 2015, 5:01:13 AM4/29/15
to mongodb...@googlegroups.com
Hi,

Using the new C# driver (2.0), I'm trying to atomically FindAndModify a document, where an existing sub document with a specific property value doesn't already exist.

Take this model:

{ 
    _id:1,
    subdocs: [
        { ref:1,val:'1'},
        { ref:2,ref:'2'}
    ]
}
I want to $addtoset to subdocs where the a sub document with a ref doesn't already exist.

var filterId = Builders<Organisation>.Filter.Eq(p => p.Id, 1);
var filterNotExist = Builders<Organisation>.Filter.???(*???*);
var filterAnd = Builders<Organisation>.Filter.And(filterId,filterNotExist);
var update = Builders<Organisation>.Update.AddToSet(p => p.Facilities, facility);
return await GetCollection().FindOneAndUpdateAsync(filterAnd, update);

I thought about doing a Not filter on an AnyEq, but unsure of syntax.

To complicate things further how would I do the same for another nested sub document?

Many thanks
Sam

Craig Wilson

unread,
Apr 29, 2015, 10:28:26 AM4/29/15
to mongodb...@googlegroups.com
Hi Sam,

I'm not fully understanding what you want to do. If you are looking for not exists, then it should just be ...Filter.Exists("field", false); -> http://api.mongodb.org/csharp/2.0/html/Overload_MongoDB_Driver_FilterDefinitionBuilder_1_Exists.htm

Craig

Sam Martin

unread,
Apr 29, 2015, 11:49:52 AM4/29/15
to mongodb...@googlegroups.com
Hi Craig,

I want to add a sub document to array if a matching sub document doesn't already exist.  This is done on a single property.
I want to do this find and update in a single call to avoid the the data changing between checking and updating.

Does that make more sense?

I'm just trying a Not ( AnyEq ) but not sure on what's the easiest/best way with the driver.

thanks
sam

Sam Martin

unread,
Apr 29, 2015, 7:54:58 PM4/29/15
to mongodb...@googlegroups.com
Hi Craig,

Have you got an example of matching property of sub document array using AnyEq()?



--
You received this message because you are subscribed to the Google Groups "mongodb-csharp" group.
To unsubscribe from this group and stop receiving emails from it, send an email to mongodb-cshar...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Craig Wilson

unread,
Apr 29, 2015, 8:32:01 PM4/29/15
to mongodb...@googlegroups.com
Generally, when you are having trouble figuring out the best query, it's almost always easiest to figure it out in the shell and then port it into your applications. Also, if you have it working in the shell, it's very easy for us to help you port it into .NET.

As such, I still don't completely understand exactly what you are wanting to do. It's possible you are looking for $elemMatch: http://docs.mongodb.org/manual/reference/operator/query/elemMatch/.

var builder = Builders<Organization>.Filter;
var filter = builder.Not(builder.ElemMatch(x => x.SubDocs, subDoc => subDoc.Ref == "K" && subDoc.Value == 10));

If this still isn't what you are looking for, see if you can get it working in the shell and I can help translate into .NET.

Craig
To unsubscribe from this group and stop receiving emails from it, send an email to mongodb-csharp+unsubscribe@googlegroups.com.

Sam Martin

unread,
May 1, 2015, 4:22:46 AM5/1/15
to mongodb...@googlegroups.com
that is it!

thanks craig
To unsubscribe from this group and stop receiving emails from it, send an email to mongodb-cshar...@googlegroups.com.

Sam Martin

unread,
May 1, 2015, 12:02:36 PM5/1/15
to mongodb...@googlegroups.com
sorry Craig,

that worked great!

but I have another query, what would be the syntax for performing the same query but with another nested document array?

say i have :

{ 
    _id:1,
    subdocs: [
        { ref:1,val:'1', subsubdocs: [{ name: '1.1'}, { name: '1.2'} ]},
        { ref:2,ref:'2', subsubdocs: [{ name: '2.1'}, { name: '2.2'} ]}
    ]
}
I need to do the same thing but where the subsubdocs name not already existing.

I've tried another number of permutations with the driver, but can't suss it out

Sam Martin

unread,
May 1, 2015, 2:35:39 PM5/1/15
to mongodb...@googlegroups.com
This would be an equiv shell cmd

db.test.update(
    {_id: '1', 'subdocs.ref': 1, 'subdocs.subsubdocs.name': {$nin: ['1.3']}},
{$push: {'subdocs.$.subsubdocs': {name: '1.3'} } }
)

Craig Wilson

unread,
May 1, 2015, 3:20:17 PM5/1/15
to mongodb...@googlegroups.com
You are probably just going to need to resort to strings. When you get this complex, the MongoDB query language doesn't really map to static types very well.

var builder = Builders<Organization>.Filter;
var filter = builder.Nin("Subdocs.SubSubDocs.Name", new [] { "1.3" }) & builder.Eq(x => x.Id, "1") & builder.Eq("Subdocs.Ref", 1);

If you use the property names in your class, we'll still translate them if you have mapped the properties to a different element.

And finally, there is always the fallback of just constructing a new BsonDocument() and building it up.
To unsubscribe from this group and stop receiving emails from it, send an email to mongodb-csharp+unsubscribe@googlegroups.com.

Sam Martin

unread,
May 1, 2015, 6:11:21 PM5/1/15
to mongodb...@googlegroups.com
Thanks Craig, was trying to do it using typed syntax

Sam Martin

unread,
May 1, 2015, 6:11:40 PM5/1/15
to mongodb...@googlegroups.com
works well without as per your example
Reply all
Reply to author
Forward
0 new messages