简体   繁体   中英

In MongoDb, how can you set a value on an object in a array property?

My goal is to put a "deleted at" timestamp on specific object in an array of a document.

If the document looks like this:

{   
    "subdoc": [
        {
            "key": 1,
            "value": "abc",
            "isActive": true
        },
        {
            "key":5,
            "value": "ade",
            "isActive":true
        }
    ]
}

I would like to be able to say "look for the document that has subdoc.key == 5 and subdoc.value == "ade"; set subdoc.isActive to false and set subdoc.deleteAt = current db timestamp. With a resulting document like this:

{   
    "subdoc": [
        {
            "key": 1,
            "value": "abc",
            "isActive": true
        },
        {
            "key":5,
            "value": "ade",
            "isActive": false,
            "deletedAt": Timestamp(1425911075,1)
        }
    ]
}

Is this doable?

Update: After further review of the mongo docs, this does seem doable with the "$ (update)" operator. That gets me what I need, but I'm hoping for a less magical-strings way of doing this using the C# driver?

My working find/update looks like this:

// find
{
    "subdoc.key":"2",
    "subdoc.value":"ade"
}
// update
{   
    "$currentDate": {
        "subdoc.$.deleteAt": {
            "$type": "timestamp"
        }
    }
}

Update: I should clarify that this updated time stamp field is used for synchronization by many sometimes-connected mobile clients in a load-balanced environment (multiple web servers, multiple worker processes, and a mongo cluster) with a high transaction volume, which makes it crucial that this time stamp has a single point truth, is logically sequential in the context of the app, and is as high precision as possible (fractions of a second). Otherwise, records could be missed in a sync.

For the moment, I'm using the above approach to ensure time stamped values are generated by the mongo database instance. And I'm pretty satisfied with this approach.

you can use the c# driver to wrap the mongo entities in c# objects. Then in your code you can use linq to query the DB and update your objects as required. Then just save them to the DB to persist your changes.

Below is a small piece of code to query a Parent collection in the test DB. The C# driver provides as AsQueryable extension to allow us to write our queries directly in Linq. The driver will then automatically build the required query and execute it against the collection.

The sample below looks for any sub documents in the subdoc list that have a value on the key field of 5

If it finds any, it updates the deletedAt date and then saves it back to the DB.

var client = new MongoClient();
var database = client.GetServer().GetDatabase("test");
var parentCollection = database.GetCollection<Parent>("Parent");

var parent = parentCollection.AsQueryable().FirstOrDefault(p => p.subdoc.Any(f => f.key == 5));

if (parent != null)
{
    var fooList = parent.subdoc.Where(f => f.key == 5);
    foreach (var foo in fooList)
    {
        foo.deletedAt = DateTime.UtcNow;
    }
}

parentCollection.Save(parent);

Below are the two c# entities used to map to the Mongo documents. We can use the [BsonIgnoreIfNull] attribute of the mongo c# driver to only serialize the deletedAt field if it contains a value. We also use a nullable DateTime object in our code to allow nulls to be stores if required.

 public class Foo 
{
    [BsonId]
    public ObjectId Id { get; set; }
    public int key { get; set; }
    public string value { get; set; }
    public bool isActive { get; set; }

    [BsonIgnoreIfNull]
    public DateTime? deletedAt { get; set; }
}

public class Parent
{
    [BsonId]
    public ObjectId Id { get; set; }
    public List<Foo> subdoc { get; set; } 
}

See most recent update. A combination of the positional and $currentDate operators is serving my purpose.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM