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

Meteor 1.0 - Mongo queries using variables as key, including $inc

本文关键字:查询 Mongo 包括 inc 变量 Meteor      更新时间:2023-09-26

我正在使用一个大型数据集,该数据集需要有效地处理其Mongo查询。该应用程序使用福特-富尔克森算法来计算建议并在多项式时间内运行,因此效率非常重要。语法是 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.' })方面也存在问题。

我能做些什么来尽可能少的查询中做到这一点?我愿意接受建议。

编辑

我尝试创建对象以传递到 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 级来更改任何内容。

溶液

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

  _.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);
  });

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

完全规范化,你会有一个项目表和一个权重表。项目表将包含项目。权重表将具有类似于 item1item2weight 的内容(这样做,您可以有不对称的权重,例如 sharpie:pencil = 1pencil:sharpie = .5 ,这在计算 FFA 中的推回时很有用,但我认为这不适用于您的情况。

太好了,现在让我们把它蒙哥化。

当我们说 1 个项目有很多项目时,"许多"可能不会超过几千个(想想 16MB 的文档上限)。这意味着它实际上是一对一,这意味着我们可以使用子文档或字段来嵌套数据。

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

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

我们看到了什么? sharpie不是键,而是。这使一切变得容易。我们将项目保留为字段。我们不使用对象数组的原因是因为它更快、更干净(无需遍历数组以找到匹配的_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。