【问题标题】:How to query MongoDB to test if an item exists?如何查询 MongoDB 以测试项目是否存在?
【发布时间】:2022-04-05 14:34:54
【问题描述】:

MongoDB 是否提供查找或查询方法来根据任何字段值测试项目是否存在?我们只想检查是否存在,而不是返回项目的全部内容。

【问题讨论】:

    标签: mongodb find


    【解决方案1】:

    由于您不需要计数,因此您应该确保查询将在找到第一个匹配项后返回。因为count performance is not ideal,这很重要。以下查询应该完成:

    db.Collection.find({ /* criteria */}).limit(1).size();
    

    请注意,find().count() 默认情况下尊重limit 子句,因此可能会返回意外结果(并会尝试查找所有匹配项)。 size()count(true) 将遵守限制标志。

    如果你想走极端,你应该确保你的查询使用covered indexes。覆盖索引仅访问索引,但它们要求您查询的字段已编入索引。一般来说,应该这样做,因为 count() 显然不返回任何字段。不过,覆盖索引有时需要相当冗长的游标:

    db.values.find({"value" : 3553}, {"_id": 0, "value" : 1}).limit(1).explain();
    
    {
      // ...
      "cursor" : "BtreeCursor value_1",
      "indexOnly" : true,  // covered!
    }
    

    很遗憾,count() 不提供explain(),所以值得与否很难说。像往常一样,测量是比理论更好的伴侣,但理论至少可以让你摆脱更大的问题。

    【讨论】:

    • db.Collection.find({ /* criteria */}).limit(1).size(); 同步吗?
    • 你想要.count(with_limit_and_skip=True)。没有方法叫.size()
    • 好像没有 .size() 方法
    【解决方案2】:

    我不相信有直接的方法可以通过它的价值来检查项目的存在。但是您可以通过仅检索 id (with field selection) 来做到这一点

    db.your_collection.find({..criteria..}, {"_id" : 1});
    

    【讨论】:

    • 我使用 findOne 超过 find
    • 谢谢。由于所有的 ID 都在内存中被索引,这个查询会对磁盘做任何事情吗?
    【解决方案3】:

    Mongo 2.6开始,count 有一个limit 可选参数,这使它成为查找文档是否存在的可行替代方案:

    db.collection.count({}, { limit: 1 })
    // returns 1 if exists and 0 otherwise
    

    或使用过滤查询:

    db.collection.count({/* criteria */}, { limit: 1 })
    

    限制匹配出现的次数会使集合扫描在找到匹配项时停止,而不是遍历整个集合。


    Mongo 4.0.3开始,因为count()considered deprecated,我们可以用countDocuments代替:

    db.collection.countDocuments({}, { limit: 1 })
    

    或使用过滤查询:

    db.collection.countDocuments({/* criteria */}, { limit: 1 })
    

    【讨论】:

      【解决方案4】:

      使用 find() + limit() 明显更快,因为 findOne() 如果存在,将始终读取 + 返回文档。查找()只是 返回游标(或不返回)并且仅在迭代时读取数据 通过光标。

      db.collection.find({_id: "myId"}, {_id: 1}).limit(1)

      (而不是db.collection.findOne({_id: "myId"}, {_id: 1}))。

      查看更多详情:Checking if a document exists – MongoDB slow findOne vs find

      【讨论】:

      • find() 将始终返回一个光标(即使文档不存在 - 在这种情况下 hasNext() 将返回 false
      【解决方案5】:
      filter_dict = {"key":value}
      if db.collection.count_documents(filter_dict):
          print("item is existed")
      else:
          print("item is not existed")
      

      【讨论】:

      • 虽然这段代码可能会解决问题,但一个好的答案还应该解释代码的什么以及它如何提供帮助。
      【解决方案6】:

      Xavier 回答的更新:

      db.collection.countDocuments({}, { limit: 1 })
      

      现在将回调作为第二个参数,因此可以使用它来代替:

      db.collection.countDocuments({}).limit(1)
      

      【讨论】:

        【解决方案7】:

        我目前正在使用这样的东西:

        async check(query) {
          const projection = { _id: 1 };
        
          return !!db.collection.findOne(query, projection);
        }
        

        它会返回真或假,当然只返回 _id: 1 用于最小的数据传输。

        【讨论】:

          【解决方案8】:

          我很惊讶这里没有提到 $exists operator

          db.collection.findOne({myFieldName: {$exists: 1}})

          如果你想要相反的(找到一个字段不存在的地方): db.collection.findOne({myFieldName: {$exists: 0}})

          如果你想得到一个光标,使用find() instad of findOne(),你可以用db.collection.find({myFieldName: {$exists: 1}}).isExhausted()得到一个布尔值

          请注意,isExhausted() 仅是 mongo shell method

          【讨论】:

            【解决方案9】:

            我只是简单地使用了 lodash 框架 - _isEmpty();

            const {
                MongoClient,
                ObjectId
            } = require('mongodb');
            const _ = require('lodash');
            
            MongoClient.connect(testURL, {
                useNewUrlParser: true
            }, (err, client) => {
                let db = client.db('mycompany');
            
                if (err) {
                    console.log('unable to connect to the mycompany database');
                } else {
                    console.log('test connection to the database');
                };
            
                db.collection('employee').find({
                    name: 'Test User'
                }).toArray((err, result) => {
            
                    if (err) {
                        console.log('The search errored');
                    } else if (_.isEmpty(result)) {
                        console.log('record not found')
                    } else {
                        console.log(result);
                    };
                });
                client.close();
            });
            

            【讨论】:

            • 如果你可以简单地做result.length === 0,为什么还要使用框架?
            【解决方案10】:

            如果你使用 Java 和 Spring,你可以使用它:

            public interface UserRepository extends MongoRepository<User, ObjectId> {
            
                boolean existsByUsername(String username);
            
            }
            

            它对我有用。

            【讨论】:

              猜你喜欢
              • 2021-08-24
              • 1970-01-01
              • 1970-01-01
              • 2019-07-28
              • 2012-02-16
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2019-06-04
              相关资源
              最近更新 更多