【问题标题】:Mongo query for comparing two indexed fields用于比较两个索引字段的 Mongo 查询
【发布时间】:2016-01-04 10:57:21
【问题描述】:

这个mongo查询有什么替代方法

db.test.findAndModify(
{
   query:{$where:"this.field1<this.field2"},
   update:{$inc:{field2:1}},
   sort:{field2:1}
});

因为这个查询扫描了所有记录并且没有利用索引。

【问题讨论】:

  • 您实际拥有哪些索引,这些字段中的数据类型是什么?
  • { field1 : 1 }, { field2 : 1}
  • 字段是数字还是字符串?
  • 两个字段都是数字
  • 以及该查询返回的记录的大致比例是多少?

标签: mongodb indexing mongodb-query


【解决方案1】:

我建议您应该在文档中创建一个附加字段,即field2field1 之间的区别,然后在其上创建一个索引。

在您的findAndModify() 查询中增加field2(从而增加差异),您也应该增加difference 字段:

db.test.findAndModify(
{
    query: {difference: {$gt: 0}},
    update: {$inc: {field2: 1, difference: 1}}
});

【讨论】:

    【解决方案2】:

    由于 $where 将在 JavaScript 中加载和评估并且不会使用任何索引,因此您最好的选择是在您的文档架构中创建一个额外的布尔字段,例如 "isField2GreaterThanField1"保存布尔结果(field1 &lt; field2)

    要创建额外字段,您必须迭代 find() 操作的结果并在循环中更新集合:

    db.test.find({}).forEach(function(doc) { 
        var comparison = (doc.field1 < doc.field2);
        db.test.update(
            { "_id": doc._id }, 
            {
                "$set": { 
                    "isField2GreaterThanField1": comparison  
                }
            }
        );
    });
    

    如果处理大型集合,上述更新操作的性能可能会受到影响,但是使用 Bulk API 可以通过减少发送到服务器的更新操作量来简化更新以最大限度地提高效率,每 1000 个排队操作发送一次:

    var bulk = db.test.initializeOrderedBulkOp(),   
        counter = 0;
    
    db.test.find({}).forEach(function(doc) { 
        var comparison = (doc.field1 < doc.field2);    
        bulk.find({ "_id": doc._id }).updateOne({
            "$set": { 
                "isField2GreaterThanField1": comparison 
            }
        });
    
        counter++;
        if (counter % 1000 == 0) {
            // Execute per 1000 operations and re-initialize every 1000 update statements
            bulk.execute();
            bulk = db.test.initializeOrderedBulkOp();
        }
    });
    
    // Clean up queues
    if (counter % 1000 != 0){
        bulk.execute();
    }
    

    创建新字段后,您可以在其上创建索引并查询您的文档,如下所示

    db.test.find({"isField2GreaterThanField1": true});
    

    【讨论】:

      【解决方案3】:

      根据documentation$where 运算符要求数据库为集合中的每个文档处理 JavaScript 表达式或函数。这意味着表达式 "this.field1&lt;this.field2" 被视为 JavaScript 表达式,因此不使用索引。

      您不能使用find 查询在本地(没有 JavaScript)比较 MongoDB 中的两个字段,但是,您可以为此目的使用聚合框架。通过使用$match 运算符,您可以执行类似于下面的 sn-p 的操作:

      db.data.aggregate([{
         $project : {
              equal : {
                 $eq : ["$field1", "$field2"]  
             },
             doc : "$$ROOT"   // store the whole document, this is optional
         }
      }, {
          $match : {
             equal : true   
          }
      }]);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-01-31
        • 1970-01-01
        • 2017-02-12
        • 1970-01-01
        • 2017-12-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多