【问题标题】:Creating a MongoDB query (with Mongoose) with unknown number of conditions使用未知数量的条件创建 MongoDB 查询(使用 Mongoose)
【发布时间】:2015-09-21 09:50:01
【问题描述】:

假设我有以下文件

{colors: [red, blue, green]}
{colors: [yellow, brown, green]}
{colors: [purple]}
{colors: [red, blue, orange]}

我想创建一个函数来查询集合中的文档,这些文档在输入中至少具有一种颜色,这是一个数组。例如,如果我想找到一个红色、蓝色和/或绿色的文档,我会写

findColors([red, blue, green])

它会返回

{colors: [red, blue, green]}
{colors: [red, blue, orange]}
{colors: [yellow, brown, green]}

在上面的顺序中,最完美匹配的文档排在第一位,最不完美匹配的文档排在最后。我的问题是数组中的元素数量是任意的,所以我不知道如何在没有循环的情况下将它们组合成一个查询。直接传入数组的问题是它只会返回

{colors: [red, blue, green]}

但我想要尽可能多的匹配项。另外,数组中的顺序应该无关紧要。

有没有办法 1) 将多个独立查询合并为一个大查询 2) 在数组上使用某种模式匹配函数,以便创建数组元素的所有可能组合,然后我可以将其传递给函数。

另外,为了缩短运行时间,我想只写“找到 10 个文档后停止运行”

【问题讨论】:

    标签: node.js mongodb mongoose mongodb-query aggregation-framework


    【解决方案1】:

    您不需要循环查询或任何类似的事情。提交多个项目以使用数据库进行测试称为$or 条件,或者在这种情况下,它可以显式缩短为$in,给定输入列表以匹配类似的值列表。这将返回包含针对比较字段列出的任何值的文档,在这种情况下,它也是一个数组。

    唯一需要做的就是将公共元素与公共元素的数量相匹配。这里可以使用聚合框架的$setIntersection 运算符来匹配元素以及$size 以返回匹配列表的大小。

    这有效地通过匹配元素对文档“评分”,这些元素可以传递给$sort 以首先返回最多匹配。然后唯一要求的另一件事是“在 10 点停止”,这是 $limit 操作对结果所做的。

    作为一个完整的例子:

    var async = require('async'),
        mongoose = require('mongoose'),
        Schema = mongoose.Schema;
    
    mongoose.connect('mongodb://localhost/test');
    
    var data = [
      { "colors": [ "red", "blue", "green" ] },
      { "colors": [ "yellow", "brown", "green" ] },
      { "colors": [ "purple" ] },
      { "colors": [ "red", "blue", "orange" ] }
    ];
    
    
    var colorSchema = new Schema({
      "colors": []
    });
    
    var Color = mongoose.model('Color',colorSchema);
    
    function findColors(list,callback) {
      Color.aggregate(
        [
          { "$match": { "colors": { "$in": list } } },
          { "$project": {
            "colors": 1,
            "score": {
              "$size": {
                "$setIntersection": [ "$colors", list ]
              }
            }
          }},
          { "$sort": { "score": -1 } },
          { "$limit": 10 }
        ],
        callback
      );
    }
    
    
    async.series(
      [
        function(callback) {
          Color.remove({},callback);
        },
        function(callback) {
          async.each(data,function(item,callback) {
            console.log(item);
            Color.create(item,callback);
          },callback);
        },
        function(callback) {
          console.log("here");
          findColors(["red","blue","green"],function(err,result) {
            console.log(result);
            callback(err);
          });
        }
      ],
      function(err) {
        if (err) throw err;
        mongoose.disconnect();
      }
    )
    

    产生输出:

    [ { _id: 55ff60dc683554e114f90bf2,
        colors: [ 'red', 'blue', 'green' ],
        score: 3 },
      { _id: 55ff60dc683554e114f90bf5,
        colors: [ 'red', 'blue', 'orange' ],
        score: 2 },
      { _id: 55ff60dc683554e114f90bf3,
        colors: [ 'yellow', 'brown', 'green' ],
        score: 1 } ]
    

    因此,匹配最多的文档位于顶部,匹配较少的文档位于下方。此外,任何与列表不匹配的内容都将被排除在外。

    【讨论】:

      猜你喜欢
      • 2016-09-21
      • 1970-01-01
      • 2015-07-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-05-20
      • 1970-01-01
      • 2018-10-25
      相关资源
      最近更新 更多