我正在使用一个需要通过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 回答
我认为问题来自你的ER模型 .
sharpie
不是一个独立的实体,一个sharpie是一个项目 . 1项与其他项之间的关系是1项具有多项(1:M递归)并且每项配对具有权重 .完全标准化,你有一个物品表和一个重量表 . items表将包含这些项目 . 权重表会有
item1
,item2
,weight
(在这样做时,你可以有非对称加权,例如sharpie:pencil = 1
,pencil:sharpie = .5
,这在计算FFA中的后推时很有用,但我不认为这适用于你的情况 .太棒了,现在让我们把它搞得一团糟 .
当我们说1项有很多项目时,“很多”可能不会超过几千(想想16MB文件上限) . 这意味着它实际上是1对少,这意味着我们可以使用subdocs或字段来嵌套数据 .
那么,让我们看看这个架构!
我们看到了什么?
sharpie
isn 't a key, it'是一个值 . 这使一切变得简单 . 我们将这些项目保留为字段 . 我们不使用对象数组的原因是因为它更快更干净(无需迭代数组以找到匹配的_id
) .这很容易 . 困难的部分是弄清楚为什么要使用FFA作为建议引擎:-P .