问题描述
我们正在尝试创建对MangoDB的调用,以接收所有可能的产品过滤器。
we are trying to create call to MangoDB to receive all possible filters for products.
我将尝试创建我们产品的示例
I will try to create example of our products
第一个产品是阿迪达斯运动鞋,它有两个选择-颜色和尺寸。但是对于不同的颜色,您有不同的尺寸。
First product is Adidas Shoes which have two options to select - colour and size. But for different colours you have different sizes.
{
id: 1
name: "Adidas Shoes",
filters: [
[
{
code: "brand",
value: "Adidas"
},
{
code: "colour",
value: "white"
},
{
code: "size",
value: 41
}
],
[
{
code: "brand",
value: "Adidas"
},
{
code: "colour",
value: "white"
},
{
code: "size",
value: 42
}
],
[
{
code: "brand",
value: "Adidas"
},
{
code: "colour",
value: "white"
},
{
code: "size",
value: 43
}
],
[
{
code: "brand",
value: "Adidas"
},
{
code: "colour",
value: "blue"
},
{
code: "size",
value: 41
}
],
[
{
code: "brand",
value: "Adidas"
},
{
code: "colour",
value: "blue"
},
{
code: "size",
value: 44
}
]
]
}
Secon d产品为耐克鞋。
Second product is Nike Shoes.
{
id: 2
name: "Nike Shoes",
filters: [
[
{
code: "brand",
value: "Nike",
},
{
code: "colour",
value: "white",
},
{
code: "size",
value: 41,
}
],
[
{
code: "brand",
value: "Nike",
},
{
code: "colour",
value: "white",
},
{
code: "size",
value: 42,
}
],
[
{
code: "brand",
value: "Nike",
},
{
code: "colour",
value: "green",
},
{
code: "size",
value: 41,
}
]
]
}
和Reebook鞋子
{
id: 3
name: "Reebook Shoes",
filters: [
[
{
code: "brand",
value: "Reebook",
},
{
code: "colour",
value: "black",
},
{
code: "size",
value: 41,
}
]
]
}
大小取决于颜色,颜色取决于大小。
as you can see option size is dependent on colour and colour is dependent on size.
我们如何创建MongoDb.aggregate以具有所有可能的滤镜?
How we can create MongoDb.aggregate to have all possible filters?
品牌:阿迪达斯(1),耐克(1),Reebook(1)
Brand: Adidas (1), Nike (1), Reebook (1)
尺寸: 41(3),42(2),43(1),44(1)
Size: 41 (3), 42 (2), 43 (1), 44 (1)
颜色:白色(2),蓝色(1),绿色(1),黑色(1)
Colour: White (2), Blue (1), Green (1), Black (1)
并且通话应独立关于我们有多少个过滤器(带有一个选项的产品,具有更多选项的产品和不同的过滤器)。您能解释一下在这种情况下如何使用$ group,$ unwind吗?以及我们以后如何使用$ facet改善它?
And call should be independent on how many and which filters we have (products with one option, products with more options and different filters). Can you explain how to use $group, $unwind in this situation? And how we can improve it later with $facet?
非常感谢!
编辑02/10/2017
示例响应
facets: [
{
code: "brand",
values: [
{
name: "Adidas",
count: 1
},
{
name: "Nike",
count: 1
},
{
name: "Reebook",
count: 1
}
]
},
{
code: "size",
values: [
{
name: 41,
count: 3
},
{
name: 42,
count: 2
},
{
name: 43,
count: 1
},
{
name: 44,
count: 1
}
]
},
{
code: "colour",
values: [
{
name: "White",
count: 2
},
{
name: "Blue",
count: 1
},
{
name: "Green",
count: 1
},
{
name: "Black",
count: 1
}
]
}
]
或
facets: {
"brand": {
"Adidas": 1,
"Nike":1,
"Reebook":1
},
"size": {
"41": 3,
"42":2,
"43":1,
"44":1
},
"colour": {
"White": 2,
"Blue":1,
"Green":1,
"Black":1
}
}
这是我们的第一阶段。下一步将是当我选择大小:41和颜色:白色时如何搜索可能的过滤器。
This is our first stage. Next step will be how to search possible filters when I have selected Size: 41 and Colour: White.
谢谢
推荐答案
这是一个可能对您有用的聚合。
Here is an aggregation that might work for you.
db.getCollection('test').aggregate([
{$unwind: '$filters'},
{$unwind: '$filters'},
{
$group: {
_id: {code: '$filters.code', value: '$filters.value'},
products: {$addToSet: '$_id'}
}
},
{
$project: {
'filter.value': '$_id.value',
'filter.count': {$size: '$products'}
}
},
{
$group: {
_id: '$_id.code',
filters: {$push: '$filter'}
}
}
]);
您需要的数据来自,因为没有简单的方法可以转换组数组
The data you need comes in a slightly different format because there's no easy way to convert array of grouped values to object properties.
如果已经选择了某些过滤器,则在第一个$ unwind之后需要另一个$ match阶段。
它还支持多选。假设我要使用Reebook / Adidas制造的白色/黑色鞋子。
If some filters are already selected you need another $match stage after the first $unwind.It also supports multi selects. Say I want white/black shoes made by Reebook/Adidas.
db.getCollection('test').aggregate([
{$unwind: '$filters'},
{
$match: {
$and: [
//Add objects here fo everything that is selected already
{'filters': {$elemMatch: {code: 'colour', value: {$in: ['black', 'white']}}}},
{'filters': {$elemMatch: {code: 'brand', value: {$in: ['Adidas', 'Reebook']}}}}
]
}
},
{$unwind: '$filters'},
{
$group: {
_id: {code: '$filters.code', value: '$filters.value'},
products: {$addToSet: '$_id'}
}
},
{
$project: {
'filter.value': '$_id.value',
'filter.count': {$size: '$products'}
}
},
{
$group: {
_id: '$_id.code',
filters: {$push: '$filter'}
}
}
]);
最后一件事是这样的依赖行为:
选择Nike => Size and Color ar e按品牌过滤,但您仍然可以选择所有品牌。
选择耐克+ 42尺寸=>您只能选择42号尺寸的颜色,颜色和42号鞋的品牌。
等等。
The last thing is the dependent behavior like this:Select Nike => Size and Color are filtered by brand but you are still able to select all brands.Select Nike + 42 Size => You can select only brands having size 42, colors and brands for which there are shoes of 42 size. And so on.
您可以利用$ facet来实现。实际上是下一个想法。
如果我们要计算品牌-我们应该按大小和颜色下拉列表中的所选内容过滤记录。
如果我们要计算尺寸-应用颜色和品牌。相同的颜色逻辑。
You can leverage $facet for it. In fact when the idea is next.If we're calculating brands - we should filter records by what's selected in size and color dropdowns.If we're calculating size - applying color and brand. Same logic for color.
以下是在mongo shell中工作的代码:
Here is the code that worked in mongo shell:
//This hash is going to by dynamic
//Add and remove properties, change $in arrays
//Depending on what user does
var conditionsForUserSelect = {
'colour': {'filters': {$elemMatch: {code: 'colour', value: {$in: ['green']}}}},
'brand': {'filters': {$elemMatch: {code: 'brand', value: {$in: ['Nike']}}}},
'size': {'filters': {$elemMatch: {code: 'size', value: {$in: [41]}}}}
};
var getFacetStage = function (code) {
//Empty object, accept all filters if nothing is selected
var matchStageCondition = {};
var selectedFilters = Object.keys(conditionsForUserSelect);
if (selectedFilters && selectedFilters.length) {
//Take all queries EXCEPT for the passed
//E.g. if we are counting brand filters then we should apply color and size.
//Because for example if no size/colour selected we should
//allow all brands even if Reebok is selected
var conditionsToApply = selectedFilters
.filter(function (key) {
return key !== code
})
.map(function (key) {
return conditionsForUserSelect[key]
});
if (conditionsToApply && conditionsToApply.length) {
matchStageCondition = {
$and: conditionsToApply
};
}
}
return [
{$unwind: '$filters'},
{
$match: matchStageCondition
},
{$unwind: '$filters'},
{
$group: {
_id: {code: '$filters.code', value: '$filters.value'},
products: {$addToSet: '$_id'}
}
},
{
$project: {
'filter.value': '$_id.value',
'filter.count': {$size: '$products'}
}
},
{
$group: {
_id: '$_id.code',
filters: {$push: '$filter'}
}
},
{
$match: {_id: code}
}
];
};
db.getCollection('test').aggregate([
{
$facet: {
colour: getFacetStage('colour'),
size: getFacetStage('size'),
brand: getFacetStage('brand')
}
}
]);
这篇关于Mongo DB中的多面过滤器,用于具有多个选项的产品的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!