我有以下文档结构:
{ _id:ID1
value: { data:{userData:{name:aaa,surname:bbb}}
events:[
{even1tName:{timestamp:UNIX_TIMESTAMP,value:NUMBER}},
{even2tName:{timestamp:UNIX_TIMESTAMP,value:NUMBER}},
{even3tName:{timestamp:UNIX_TIMESTAMP,value:NUMBER}},
{even4tName:{timestamp:UNIX_TIMESTAMP,value:NUMBER}},
],
activity:{countEvents:INTEGER,totalValue:NUMBER}
}
}
这是MapReduce管道的输出,我需要在一个时间范围内找到使用聚合,用户有一定数量的事件和一定数量的值(总结)。考虑一下这些是在线买家,我需要找到那些在过去一个月内进行了3次购买的商品或那些购买总金额超过300美元的商品。
答案 0 :(得分:1)
你的问题对信息有点关注,但主要的是,只要有一致的" keyname"在文档中命名然后这确实不是问题:
db.junk.aggregate([
// Match where type within timeframe
{ "$match": {
"value.events.confirmedSale.timestamp": {
"$gte": startTime, "$lt": endTime
}
}},
// Pre-filter the array for required data
{ "$project": {
"value": {
"data": "$value.data",
"events": {
"$setDifference": [
{"$map": {
"input": "$value.events",
"as": "el",
"in": {
"$cond": [
{ "$and": [
{ "$gte": [ "$$el.confirmedSale.timestamp", startTime ] },
{ "$lt": [ "$$el.confirmedSale.timestamp", endTime ] }
]},
"$$el",
false
]
}
}},
[false]
]
}
}
}},
// Unwind array elements for processing
{ "$unwind": "$value.events" },
// Group data
{ "$group": {
"_id": "$_id",
"value": { "$sum": "$value.events.confirmedSale.value"},
"count": { "$sum": 1 }
}},
// Filter results on totals
{ "$match": {
"value": { "$gte": 300, "count": { "$gte": 3 } }
}}
])
但是,由于文档结构的原因,您无法真正获得更广泛的内容。这样的命名需要"路径名称"嵌入对象是绝对的,这种特殊情况对索引也不好。
通过对文档创建的一些控制,它应该看起来更像这样:
{ _id: 1,
value: {
data:{
userData:{name:"aaa",surname:"bbb"}
},
events:[
{ "type": "adCLick", "timestamp": 1234, "value": 1234 },
{ "type": "confirmedSale", "timestamp": 5678, "value": 5678 },
{ "type": "confirmedSale", "timestamp": 4567, "value": 4567 },
{ "type": "something", "timestamp": 9876, "value": 9876}
]
}
}
现在你在这里使用的字段名称实际上只是一个一致的"数据"属性,查询可以更清晰地读取,使用您无法执行的组合事件执行更多操作,并且还可以使用索引来提高性能。
MongoDB主要是一个"数据库",如果你没有保持一致的命名路径,那么你将会有性能和功能损失。聚合框架是"高性能"使用JavaScript在mapReduce上选项。对于聚合框架,使用set key模式是合适的,但是如果你改变了那个模式,那么你唯一的选择就是mapReduce。