首页 文章

Meteor 1.0 - 使用变量作为键的Mongo查询,包括$ inc

提问于
浏览
3

我正在使用一个需要通过Mongo查询高效的大型数据集 . 该应用程序使用Ford-Fulkerson算法计算推荐值并在多项式时间内运行,因此效率非常重要 . 语法是ES6,但一切都基本相同 .

这是我正在使用的数据的近似值 . 一系列项目和一个项目与其他项目匹配:

let items = ["pen", "marker", "crayon", "pencil"];
let match = "sharpie";

最终,我们将迭代 match 并将配对的权重增加1.因此,在完成该功能后,我的理想数据如下所示:

{
  sharpie: {
    pen: 1,
    marker: 1,
    crayon: 1,
    pencil: 1
  }
}

为了进一步说明,每个键旁边的值是该关系的 weight ,也就是说,这些项已配对在一起的次数 . 我想要发生的事情是这样的:

// For each in the items array, check to see if the pairing already
// exists. If it does, increment. If it does not, create it.
_.each(items, function(item, i) {  
  Database.upsert({ match: { $exist: true }}, { match: { $inc: { item: 1 } } });
})

当然,问题是Mongo不允许使用括号表示法,也不允许将变量名称作为键( match ) . 正如我所知,另一个问题是Mongo在嵌套的 $inc 运算符( 'The dollar ($) prefixed field \'$inc\' in \'3LhmpJMe9Es6r5HLs.$inc\' is not valid for storage.' } )中也存在问题 .

我能做些什么来尽可能少地进行查询?我愿意接受建议 .

EDIT

我试图创建传递给Mongo查询的对象:

_.each(items, function(item, i) {
        let selector = {};
        selector[match] = {};
        selector[match][item] = {};

        let modifier = {};
        modifier[match] = {};
        modifier[match]["$inc"] = {};
        modifier[match]["$inc"][item] = 1

        Database.upsert(selector, modifier);

不幸的是,它仍然无效 . $inc 打破了查询,它不会让我超过1级深度来改变任何东西 .

Solution

这是我最终实现的功能 . 它就像一个魅力!谢谢马特 .

_.each(items, function(item, i) {

    let incMod = {$inc:{}};
    let matchMod = {$inc:{}};

    matchMod.$inc[match] = 1;
    incMod.$inc[item] = 1;

    Database.upsert({node: item}, matchMod);
    Database.upsert({node: match}, incMod);
  });

1 回答

  • 2

    我认为问题来自你的ER模型 . sharpie 不是一个独立的实体,一个sharpie是一个项目 . 1项与其他项之间的关系是1项具有多项(1:M递归)并且每项配对具有权重 .

    完全标准化,你有一个物品表和一个重量表 . items表将包含这些项目 . 权重表会有 item1item2weight (在这样做时,你可以有非对称加权,例如 sharpie:pencil = 1pencil:sharpie = .5 ,这在计算FFA中的后推时很有用,但我不认为这适用于你的情况 .

    太棒了,现在让我们把它搞得一团糟 .

    当我们说1项有很多项目时,“很多”可能不会超过几千(想想16MB文件上限) . 这意味着它实际上是1对少,这意味着我们可以使用subdocs或字段来嵌套数据 .

    那么,让我们看看这个架构!

    doc =
    {
      _id: "sharpie",
      crayon: 1,
      pencil: 1
    }
    

    我们看到了什么? sharpie isn 't a key, it'是一个值 . 这使一切变得简单 . 我们将这些项目保留为字段 . 我们不使用对象数组的原因是因为它更快更干净(无需迭代数组以找到匹配的 _id ) .

    var match = "sharpie";
    var items = ["pen", "marker", "crayon", "pencil"];
    var incMod = {$inc:{}};
    var matchMod = {$inc:{}};
    matchMod.$inc[match] = 1;
    for (var i = 0; i < items.length; i++) {
      Collection.upsert({_id: items[i]}, matchMod);
      incMod.$inc[items[i]] = 1;  
    }
    Collection.upsert({_id: match}, incMod);
    

    这很容易 . 困难的部分是弄清楚为什么要使用FFA作为建议引擎:-P .

相关问题