【问题标题】:Query MongoDB Using 'ObjectId'使用“ObjectId”查询 MongoDB
【发布时间】:2013-01-14 09:15:22
【问题描述】:

我在没有id 的情况下将documents 插入了MongoDB。我想通过搜索他们的MongoDB ObjectId 来检索他们,这是默认分配的。

这是我的尝试-

var query_id = Query.EQ("_id", "50ed4e7d5baffd13a44d0153");
var entity = dbCollection.FindOne(query_id);
return entity.ToString();

我得到以下错误-

发生“System.NullReferenceException”类型的第一次机会异常

有什么问题?

【问题讨论】:

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


    【解决方案1】:

    您需要创建ObjectId 的实例,然后使用该实例进行查询,否则您的查询会将ObjectIds 与字符串进行比较,而无法找到匹配的文档。

    这应该可行:

    var query_id = Query.EQ("_id", ObjectId.Parse("50ed4e7d5baffd13a44d0153"));
    var entity = dbCollection.FindOne(query_id);
    return entity.ToString();
    

    【讨论】:

    • 这个答案几乎是正确的。至少在 C# 中,似乎不再有 FindOne() 方法。将其替换为 FindOneAs()。这是一个很好的例子的链接,这个使用 FindAs(),但原理相同:stackoverflow.com/a/12345580/2705003
    • 现在不再有 FineAs 或 FindOneAs 方法,而是应该引用 Minhas Kamal 的答案
    • 正如灵魂检查所提到的。 _id 字段不是字符串,而是更复杂的数据类型,称为 ObjectId。
    【解决方案2】:

    在C#中为最新的官方MongoDB.Driver写这个-

    var filter_id = Builders<MODEL_NAME>.Filter.Eq("id", ObjectId.Parse("50ed4e7d5baffd13a44d0153"));
    var entity = dbCollection.Find(filter).FirstOrDefault();
    return entity.ToString();
    

    我们可以在不将id 从字符串转换为ObjectId 的情况下完成相同的结果。但是,我们将不得不在模型类中的id 属性之前添加[BsonRepresentation(BsonType.ObjectId)]。

    代码甚至可以使用 lambda 表达式-

    进一步简化
    var entity = dbCollection.Find(document => document.id == "50ed4e7d5baffd13a44d0153").FirstOrDefault();
    return entity.ToString();
    

    【讨论】:

    • 在ObjectId.Parse(cool_id.ToString()) 上,我不断发现 guid 是“不是有效的 24 位十六进制字符串”——我做错了什么?
    • @VincentBuscarello,正如它所说,您的 cool_id 没有有效的字符串表示。可能使用 ObjectId.TryParse(cool_id.ToString(), out ObjectId parsedResult) 代替?
    【解决方案3】:

    如果您在 2018 年来到这里并且想要复制/粘贴仍然有效的代码或纯字符串语法;

        [Fact]
        public async Task QueryUsingObjectId()
        {
            var filter = Builders<CosmosParkingFactory>.Filter.Eq("_id", new ObjectId("5b57516fd16cb04bfc35fcc6"));
            var entity = stocksCollection.Find(filter);
            var stock = await entity.SingleOrDefaultAsync();
            Assert.NotNull(stock);
    
            var idString = "5b57516fd16cb04bfc35fcc6";
            var stringFilter = "{ _id: ObjectId('" + idString + "') }";
            var entityStringFiltered = stocksCollection.Find(stringFilter);
            var stockStringFiltered = await entityStringFiltered.SingleOrDefaultAsync();
            Assert.NotNull(stockStringFiltered);
        }
    

    【讨论】:

      【解决方案4】:

      选择的答案是正确的。对于任何对 Query.EQ 感到困惑的人,这里有另一种编写基本更新的方法(更新整个 mongodb 文档):

      string mongoDocumentID = "123455666767778";
      var query = new QueryDocument("_id", ObjectId.Parse(mongoDocumentID)); 
      var update = new UpdateDocument { { "$set", documentToSave } };
      mongoCollection.Update(query, update, UpdateFlags.Multi);
      

      ObjectId 对象是需要实际按对象 ID 搜索时,否则是字符串与 objectid 类型的比较,不匹配。 Mongo 在这种方式下对类型非常严格,无论字段名称是否正确。

      【讨论】:

        【解决方案5】:

        你也可以这样做,它的

        public static ObjectId GetInternalId(string id)
            {
                if (!ObjectId.TryParse(id, out ObjectId internalId))
                    internalId = ObjectId.Empty;
        
                return internalId;
            }
        

        然后在你的方法中你可以做这样的事情

        ObjectId internalId = GetMongoId.GetInternalId(id);
                return await YourContext.YourTable.Find(c => c.InternalId == internalId).FirstOrDefaultAsync();
        

        注意:GetInternalId 中的 id 参数是该方法的参数。如果您需要这样:

        public async Task<YourTable> Find(string id)
            {
                ObjectId internalId = GetMongoId.GetInternalId(id);
                return await YourContext.YourTable.Find(c => c.InternalId == internalId).FirstOrDefaultAsync();
            }
        

        希望它也有帮助。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-07-22
          • 1970-01-01
          • 2015-03-13
          • 2021-05-09
          • 2019-09-22
          • 2014-12-13
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多