可以在MongoCollection上将Find()调用多次吗?

时间:2016-11-11 12:47:44

标签: c# mongodb

我正在尝试使用另一个对象(MyObject)上的属性值更新对象数组中每个对象的属性。我不清楚是否打电话:

my_objects_collection = m_database.GetCollection(MY_OBJECTS_COLLECTION_NAME);

有任何性能影响,所以我尝试只调用一次并在For ... Loop中对它执行一个新的Find命令(每次迭代都有一个修改过的过滤器),见下文:

            MyObject my_object = null;
            IMongoCollection<MyObject> my_objects_collection = null;

            if (objects != null)
            {
               my_objects_collection = m_database.GetCollection<MyObject>(MY_OBJECTS_COLLECTION_NAME);

                for (int i = 0; i < objects.Count; i++)
                {
                    Expression<Func<MyObject, bool>> filter = x => (x.ID == objects[i].ID) && (x.LanguageCode == language_code);

                    my_object = await my_objects_collection.Find(filter).FirstOrDefaultAsync();

                    if (my_object != null)
                    { objects[i].DisplayName = my_object.Name; }
                }
            }

但是,上面的代码会抛出以下异常:

值不能为空。 参数名称:集合

在MongoDB.Driver.Core.Misc.Ensure.IsNotNull [T](T值,String paramName) 在MongoDB.Driver.IMongoCollectionExtensions.Find [TDocument](IMongoCollection 1 collection, Expression 1过滤器,FindOptions选项)

如果我在for循环中移动my_objects_collection赋值,以便为每次迭代调用它,代码就可以运行而不会抛出任何异常。

因此我的问题是,对其执行查找(或任何其他操作)后,MongoCollection引用(my_objects_collection)会发生什么?

如果有人能对此提供一些见解,我真的很感激。我可以继续,因为我的应用程序正在运行,但我真的想知道为什么它抛出一个异常,表明该集合为我自己的理解为空。

提前谢谢你,

安德鲁

1 个答案:

答案 0 :(得分:1)

无论您的异常如何,您都不需要为检索的每条记录执行查找,您可以使用$ in运算符来实现此目的。

然后,您可以循环结果集并对每个文档执行更新。这样做效率要高得多,因为您要对数据库执行单个操作以返回记录,然后为每个更新执行一个操作。而不是每个检索一个,每个更新一个。

Builders<MyObject>.Filter.In

此外,如果要匹配嵌入式阵列中的元素,可以使用

Builders<MyObject>.Filter.ElemMatch

快速(未经测试)的例子

if (objects != null)
{
    var my_objects_collection = m_database.GetCollection<MyObject>(MY_OBJECTS_COLLECTION_NAME);

    var filterBuilder = Builders<MyObject>.Filter;

    var inFilter = filterBuilder.In(x => x.ID, objects.Select(x => x.ID));
    var andFilter = filterBuilder.And(
        inFilter, 
        filterBuilder.Eq(x => x.LanguageCode, language_code)
    );

    var results = await my_objects_collection.Find(andFilter).ToListAsync();

    foreach(var result in results)
    {
        //result is going to the a database object returns which matched your filter
    } 
}