Meteor应用程序,我有一个带有标签字段的mongo集合。
[{name: "ABC", tags: {"@Movie", "#free", "!R"}},
{name: "DEF", tags: {"@Movie", "!PG"}},
{name: "GHI", tags: {"@Sports", "#free"}}]
在我的用户界面上,根据标记名称的第一个字母,有三组复选框即时填充。
filter group 1: [ ]Movie [ ] Sports
filter group 2: [ ]free
filter group 3: [ ]PG [ ]R
过滤器逻辑如下:
我正在努力构建遵循上述逻辑的mongo标准参数。我的代码目前看起来像意大利面,有很多嵌套ifs(伪代码)
如果(filter_group1为空)则if(filter_group2为空)然后mongo_criteria = {_id:$ in:$(“input:checked”,“。filtergroup1”)。map(function(){return this.value} )}
这样做的正确方法是什么?
答案 0 :(得分:2)
首先,我确定你的意思是"标签"实际上是一个数组,否则结构将无效:
{ "name": "ABC", "tags": ["@Movie", "#free", "!R"]},
{ "name": "DEF", "tags": ["@Movie", "!PG"]},
{ "name": "GHI", "tags": ["@Sports", "#free"]}
存储"标签"这是一个新颖的想法。这样的数据,但似乎构建查询的程序逻辑似乎需要知道至少有三个"三个"需要在$and
组合中考虑的可能条件。
在最简单的形式中,您只允许每个过滤器组进行一次选择,然后您可以通过$all
运算符来解决此问题。只是简单的MongoDB shell表示法简洁:
db.collection.find({ "tags": { "$all": [ "@Movie", "!R" ] } })
问题在于,如果你想在一个组上进行多次选择,例如说评级,那么这将无法得到结果:
db.collection.find({ "tags": { "$all": [ "@Movie", "!R", "!PG" ] } })
实际上没有任何项目包含这些评级值,因此这将无效。所以你宁愿这样做:
db.collection.find({ "$and": [
{ "tags": { "$in": [ "@Movie" ] } },
{ "tags": { "$in": [ "!R", "!PG" ] } }
])
这样可以正确地匹配所有电影的评分标签为" R"和" PG"。将此扩展为另一个组基本上是将另一个数组项推送到$and
表达式:
db.collection.find({ "$and": [
{ "tags": { "$in": [ "@Movie" ] } },
{ "tags": { "$in": [ "!R", "!PG" ] } },
{ "tags": { "$in": [ "#free" ] }
])
仅获取包含其中每种"类型的文档"过滤器的匹配值,所以" PG"电影不是免费的"体育"通过不添加选择来过滤掉。
构建查询的基础是使用每个过滤器组中$in
的一组选择选项。当然,当您的过滤器组中存在选择时,您只会附加到$and
数组。
首先从这样的基础$and
开始:
var query = { "$and":[{}] };
然后将每个过滤器组中的每个已检查选项添加到其中:
var inner = { "tags": { "$in": [] } };
inner.tags["$in"].push( item );
然后附加到基本查询:
query["$and"].push( inner );
冲洗并重复每个项目。这是完全有效的,因为基本查询将只选择未过滤的所有内容,这也是有效的,无需构建其他逻辑:
db.collection.find({ "$and": [
{ },
{ "tags": { "$in": [ "@Movie" ] } },
{ "tags": { "$in": [ "!R", "!PG" ] } },
{ "tags": { "$in": [ "#free" ] }
])
因此,当MongoDB理解它时,它真正归结为查询的构建。这实际上只是构建数据结构时的简单JavaScript数组操作。所有MongoDB查询都是。