You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MongoDB更新嵌套属性报错:无法在null的Address字段创建子属性

问题描述

我定义了以下C#类:

public class User
{
    public Guid? Id { get; set; }
    public String? Name { get; set; }
    public Address? Address { get; set; }
}

以及Address类:

public class Address
{
    public String? Street { get; set; }
    public String? City { get; set; }
    public String? State { get; set; }
}

我在实现文档的部分更新功能,比如更新用户的City和State时,用了以下代码:

var filter = Builders<BsonDocument>.Filter.Eq("Id", id);
var updates = new List<UpdateDefinition<BsonDocument>>();
updates.Add(Builders<BsonDocument>.Update.Set("Address.City", "New City Value"));
updates.Add(Builders<BsonDocument>.Update.Set("Address.State", "New State Value"));
var update = Builders<BsonDocument>.Update.Combine(updates);
var bsonDocument = await collection.FindOneAndUpdateAsync(filter, update, new FindOneAndUpdateOptions<BsonDocument>
{
    ReturnDocument = ReturnDocument.After
});

这段代码在Address字段不为null时能正常工作,但当用户的Address字段为null时,会抛出错误:

MongoDB.Driver.MongoCommandException: Command findAndModify failed: Cannot create field 'City' in element {Address: null}.

我需要确保Address对象会被创建,从而成功设置City和State属性,而且不需要先从数据库查询当前对象。

解决方案

可以利用MongoDB的$mergeObjects操作符结合$set实现需求,它能合并现有Address对象(如果存在且不为null)与新属性值;若Address为null,则直接创建新的Address对象,无需提前查询文档。

方案1:BsonDocument字符串写法

var filter = Builders<BsonDocument>.Filter.Eq("Id", id);

// 用$mergeObjects合并现有Address(或空对象)与新的City、State
var updateDefinition = Builders<BsonDocument>.Update.Set(
    "Address",
    BsonDocument.Parse("{ $mergeObjects: [ { $ifNull: [ '$Address', {} ] }, { City: 'New City Value', State: 'New State Value' } ] }")
);

var bsonDocument = await collection.FindOneAndUpdateAsync(filter, updateDefinition, new FindOneAndUpdateOptions<BsonDocument>
{
    ReturnDocument = ReturnDocument.After
});

方案2:强类型写法(更安全)

避免直接写Bson字符串,用强类型方式构建更新定义,减少拼写错误:

var filter = Builders<User>.Filter.Eq(u => u.Id, id);

var update = Builders<User>.Update.Set(u => u.Address,
    new BsonDocument("$mergeObjects", new BsonArray
    {
        new BsonDocument("$ifNull", new BsonArray { "$Address", new BsonDocument() }),
        new Address { City = "New City Value", State = "New State Value" }.ToBsonDocument()
    })
);

var updatedUser = await collection.FindOneAndUpdateAsync(filter, update, new FindOneAndUpdateOptions<User>
{
    ReturnDocument = ReturnDocument.After
});

逻辑说明

  • $ifNull: [ '$Address', {} ]:判断当前Address字段,若为null或不存在则返回空对象{},否则返回原Address对象。
  • $mergeObjects:将前面得到的对象与包含新City、State的对象合并,既保留原Address中已有的Street等属性(如果存在),又更新目标字段;若原Address为null,则直接生成包含新属性的Address对象。

内容的提问来源于stack exchange,提问作者ScubaSteve

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 00:05:21