首页 > 解决方案 > 使用忽略 _id 的驱动程序更新文档

问题描述

我希望能够更新集合中文档中的键/值对,而不考虑_id。这个SO 响应似乎提供了一种方法来做我想做的事,但它需要关注 _id 键。

本质上,我可以做些什么来让我的代码(如下所示)在不向[BsonIgnoreExtraElements]类添加属性的情况下工作?

根据我将在下面展示的代码,我认为我已经接近了,并且我确实有一个可能的解决方法,使用我还将展示的属性。但是,如果可能的话,我想这样做而不用任何属性装饰类。

为什么没有_id?就个人而言,我发现 _id 字段妨碍了我。它不属于我的任何课程,而且 MongoDB 不是关系型的,所以我根本不使用它。我坦率地承认,我可能完全错过了使用 _id 字段背后的意图和想法,但我根本不认为 MongoDB 需要它。不过,如果可能的话,我想专注于工作而不关注 _id 字段。

话虽如此,我有检索单个文档或整个集合以及插入单个文档或整个集合的方法,一般来说,不考虑 _id 字段。

我发现在“选择”中忽略 _id 的关键是使用投影。我对驱动程序不是很熟悉,但这里有几行代码可以做到这一点:

public const string ELEMENT_ID = "_id";
ProjectionDefinition<T> projection = Builders<T>.Projection.Exclude(ELEMENT_ID);
IFindFluent<T, T> found = mongoCollection.Find(bsonDocument).Project<T>(projection);

对于背景信息,这里是一个检索方法,忽略 _id:

public T GetSingle<T>(string property, string value) where T : class, new()
        {
            T tObject = null;
            try
            {
                if (MongoContext.MongoClient != null && MongoContext.MongoDatabase != null)
                {
                    string className = typeof(T).ToString();
                    int lastPeriod = className.LastIndexOf('.');
                    int length = className.Length - lastPeriod;
                    className = className.Substring(lastPeriod + 1, length - 1);
                    if (!string.IsNullOrEmpty(className))
                    {
                        IMongoCollection<T> mongoCollection = MongoContext.MongoDatabase.GetCollection<T>(className);
                        if (mongoCollection != null)
                        {
                            BsonDocument bsonDocument = new BsonDocument();
                            ProjectionDefinition<T> projection = Builders<T>.Projection.Exclude(ELEMENT_ID);
                            PropertyInfo[] propertyInfo = typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public);
                            if (propertyInfo != null && propertyInfo.Length > 0)
                            {
                                IEnumerable<PropertyInfo> piExisting = propertyInfo.Where(pi => pi.Name.Equals(property, StringComparison.CurrentCultureIgnoreCase));
                                if (piExisting != null && piExisting.Any())
                                {
                                    BsonValue bsonValue = BsonValue.Create(value);
                                    BsonElement bsonElement = new BsonElement(property, bsonValue);
                                    if (bsonElement != null)
                                    {
                                        bsonDocument.Add(bsonElement);
                                    }
                                    IFindFluent<T, T> found = mongoCollection.Find(bsonDocument).Project<T>(projection);
                                    if (found != null)
                                    {
                                        tObject = found.FirstOrDefault<T>();
                                    }
                                }
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Logger.WriteToLog(Logger.LoggerMessage(ex));
            }
            return tObject;
        }

与其他另一个SO 响应类似,我尝试使用FindOneAndUpdate,但收到以下错误:

元素“_id”与 ClassThingy.Suffix 类的任何字段或属性都不匹配。

如果我能以FindOneAndUpdate某种方式应用投影,我认为这可能会解决我的问题,但我无法找到一种方法来执行该应用程序。

这是我的代码:

public T UpdateSingle<T>(T item, string property, object originalValue, object newValue) where T : class, new()
{
    string className = string.Empty;
    T updatedDocument = null;
    try
    {
        if (MongoContext.MongoClient != null && MongoContext.MongoDatabase != null)
        {
            className = ClassUtility.GetClassNameFromObject<T>(item);
            if (!string.IsNullOrEmpty(className))
            {
                IMongoCollection<T> mongoCollection = MongoContext.MongoDatabase.GetCollection<T>(className);
                if (mongoCollection != null)
                {
                    BsonDocument bsonDocument = new BsonDocument();
                    ProjectionDefinition<T> projection = Builders<T>.Projection.Exclude(ELEMENT_ID);
                    PropertyInfo[] propertyInfo = typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public);
                    if (propertyInfo != null && propertyInfo.Length > 0)
                    {
                        IEnumerable<PropertyInfo> piExisting = propertyInfo.Where(pi => pi.Name.Equals(property, StringComparison.CurrentCultureIgnoreCase));
                        if (piExisting != null && piExisting.Any())
                        {
                            BsonValue bsonValue = BsonValue.Create(originalValue);
                            BsonElement bsonElement = new BsonElement(property, bsonValue);
                            if (bsonElement != null)
                            {
                                bsonDocument.Add(bsonElement);
                            }
                            IFindFluent<T, T> found = mongoCollection.Find(bsonDocument).Project<T>(projection);
                            if (found != null)
                            {
                                FilterDefinition<T> filterDefinition = Builders<T>.Filter.Eq(property, originalValue);
                                UpdateDefinition<T> updateDefinition = Builders<T>.Update.Set(property, newValue);
                                updatedDocument = mongoCollection.FindOneAndUpdate<T>(filterDefinition, updateDefinition);
                            }
                        }
                    }
                }
            }
        }
    }
    catch (Exception ex)
    {
        Logger.WriteToLog(Logger.LoggerMessage(ex));
    }
    return updatedDocument;
}

有趣的是,虽然该FindOneAndUpdate方法实际上看起来成功并且“后缀”集合确实得到了修改。此外,退货不包含修改。相反,它是“原始”(当我使用如下所示的解决方法时)。

更多信息:

后缀类:

public class Suffix
{
    public string Code { get; set; }
    public string Description { get; set; }
}

在此处输入图像描述

Suffix suffix = new Suffix();
MongoRepository.MongoRepository mongoRepository = new MongoRepository.MongoRepository("MyDataBase");
mongoRepository.UpdateSingle<Suffix>(suffix, "Description", "Jr", "Junior");

解决方法:

[BsonIgnoreExtraElements]
public class Suffix
{
    public string Code { get; set; }
    public string Description { get; set; }
}

但是,如果可能的话,最好不要使用该属性。

标签: c#.netmongodbmongodb-.net-driver

解决方案


您在这里缺少的一件事.FindOneAndUpdate()是 type 的方法的第三个参数FindOneAndUpdateOptions<T,T>。这是您可以定义是否要获取文档AfterBefore修改的地方。Before是默认值此外,您可以指定投影和排除_id属性。尝试:

FilterDefinition<T> filterDefinition = Builders<T>.Filter.Eq(property, originalValue);
UpdateDefinition<T> updateDefinition = Builders<T>.Update.Set(property, newValue);
ProjectionDefinition<T, T> projection = Builders<T>.Projection.Exclude("_id");
var options = new FindOneAndUpdateOptions<T>()
{
    Projection = projection,
    ReturnDocument = ReturnDocument.After
};
updatedDocument = mongoCollection.FindOneAndUpdate<T>(filterDefinition, updateDefinition, options);

推荐阅读