如何使用官方c#驱动程序在MongoDB中使用Update.Set更新多个字段?

66
以下代码可以允许我在FirstName为"john"且LastName为"Doe"的情况下更新Email。如何更新Email和Phone,但不使用Save()方法?

以下代码将允许我在FirstName = "john"和LastName = "Doe"的情况下更新电子邮件。如何在不使用Save()方法的情况下同时更新电子邮件和电话?

MongoDB.Driver.MongoServer _server = MongoDB.Driver.MongoServer.Create("mongodb://localhost");
MongoDB.Driver.MongoDatabase _dataBase = _server.GetDatabase("test");
MongoDB.Driver.MongoCollection<Person> _person = _dataBase.GetCollection<Person>("person");

//Creat new person and insert it into collection
ObjectId newId  = ObjectId.GenerateNewId();
Person newPerson = new Person();
newPerson.Id = newId.ToString();
newPerson.FirstName = "John";
newPerson.LastName = "Doe";
newPerson.Email = "john.doe@gmail.com";
newPerson.Phone = "8005551222";
_person.Insert(newPerson);

//Update phone and email for all record with firstname john and lastname doe
MongoDB.Driver.Builders.QueryComplete myQuery = MongoDB.Driver.Builders.Query.And(MongoDB.Driver.Builders.Query.EQ("FirstName", "John"),    MongoDB.Driver.Builders.Query.EQ("LastName", "Doe"));
MongoDB.Driver.Builders.UpdateBuilder update = MongoDB.Driver.Builders.Update.Set("Email", "jdoe@gmail.com");

_person.Update(myQuery, update);
8个回答

146

非常简单;),只需在您的更新操作中添加另一个集合或其他操作:

 var update = Update.Set("Email", "jdoe@gmail.com")
                    .Set("Phone", "4455512");

哇,我从没想过那个方法,我试了几乎所有其他的方法!哈哈,谢谢! - atbebtg
如果您想更新多个N字段,请查看https://dev59.com/NW445IYBdhLWcg3wg6tm#52462098。 - Mihir Dave

44

您还可以使用通用且类型安全的Update<TDocument>

var update = Update<Person>.
    Set(p => p.Email, "jdoe@gmail.com").
    Set(p => p.Phone, "4455512");

无法工作,抱怨说:无法将lambda表达式转换为类型'FieldDefinition<T, TField>',因为它不是委托类型。 - Aquaphor

24

对于条件更新,您可以使用类似以下的内容

        var updList = new List<UpdateDefinition<MongoLogEntry>>();
        var collection = db.GetCollection<MongoLogEntry>(HistoryLogCollectionName);

        var upd = Builders<MongoLogEntry>.Update.Set(r => r.Status, status)
            .Set(r => r.DateModified, DateTime.Now);
        updList.Add(upd);

        if (errorDescription != null)
            updList.Add(Builders<MongoLogEntry>.Update.Set(r => r.ErrorDescription, errorDescription));

        var finalUpd = Builders<MongoLogEntry>.Update.Combine(updList);

        collection.UpdateOne(r => r.CadNum == cadNum, finalUpd, new UpdateOptions { IsUpsert = true });

或者只需弹出记录,然后进行修改并替换。


12

我希望更新多个N个字段,以下是我的实现方法

我使用了Builders<T>.Update.Combine

// Get the id for which data should be updated
var filter = Builders<BsonDocument>.Filter.Eq("_id", ObjectId.Parse(_id));

// Add Data which we wants to update to the List
var updateDefination = new List<UpdateDefinition<BsonDocument>>();
foreach (var dataField in metaData.Fields)
{
    updateDefination.Add(Builders<BsonDocument>.Update.Set(dataField.Name, dataField.Value));
}
var combinedUpdate = Builders<BsonDocument>.Update.Combine(updateDefination);
await GetCollectionForClient().UpdateOneAsync(filter, combinedUpdate);

4
var _personobj = _person
{
    Id = 10, // Object ID
    Email="jdoe@gmail.com",
    Phone=123456,

};
var replacement = Update<_person>.Replace(_personobj);
collection.Update(myquery, replacement);

2
如果您想更新文档的多个字段,请选择多选标志。
例如,MongoDB 2.0或3.0版本:
yourCollection.Update(_filter
                      , _update
                      , new MongoUpdateOptions() { Flags = UpdateFlags.Multi })  

1
我们可以将变量作为元组传递。
    public async Task Update(string id, params (Expression<Func<TEntity, dynamic>> field, dynamic value)[] list)
    {
        var builder = Builders<TEntity>.Filter;
        var filter = builder.Eq("_id", id);

        var updateBuilder = Builders<TEntity>.Update;
        var updates = new List<UpdateDefinition<TEntity>>();
        foreach (var item in list)
            updates.Add(updateBuilder.Set(item.field, item.value));

        var result = await _dbCollection.UpdateOneAsync(filter, updateBuilder.Combine(updates));
    }

使用方法:

await _userRepository.Update(user.id, (x => x.bio, "test"), (x => x.isEmailVerified, false));

1

您需要逐个设置每个属性。 因此,对于具有多个字段的对象,可以使用此扩展程序:

public static UpdateDefinition<T> ApplyMultiFields<T>(this UpdateDefinitionBuilder<T> builder, T obj)
    {
        var properties = obj.GetType().GetProperties();
        UpdateDefinition<T> definition = null;

        foreach (var property in properties)
        {
            if (definition == null)
            {
                definition = builder.Set(property.Name, property.GetValue(obj));
            }
            else
            {
                definition = definition.Set(property.Name, property.GetValue(obj));
            }
        }

        return definition;
    }

并且被称为这样:

public async Task<bool> Update(StaffAccount model)
    {
        var filter = Builders<StaffAccount>.Filter.Eq(d => d.Email, model.Email);

        // var update = Builders<StaffAccount>.Update.Set(d => d, model); // this doesnt work
        var update = Builders<StaffAccount>.Update.ApplyMultiFields(model);

        var result = await this.GetCollection().UpdateOneAsync(filter, update);

        return result.ModifiedCount > 0;
    }

这样做是不是每次尝试添加一个属性时都会替换掉定义,而不是添加到它上面?看起来只会更新最后一个属性。 - Sinaesthetic

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接