Leo*_*rdo 2 javascript mongoose mongodb node.js aggregation-framework
我知道很多次都会问过这个问题,但我对mongo和mongoose也有点新意,我无法理解!
我的问题:
我有一个看起来像这样:
var rankingSchema = new Schema({
userId : { type : Schema.Types.ObjectId, ref:'User' },
pontos : {type: Number, default:0},
placarExato : {type: Number, default:0},
golVencedor : {type: Number, default:0},
golPerdedor : {type: Number, default:0},
diferencaVencPerd : {type: Number, default:0},
empateNaoExato : {type: Number, default:0},
timeVencedor : {type: Number, default:0},
resumo : [{
partida : { type : Schema.Types.ObjectId, ref:'Partida' },
palpite : [Number],
quesito : String
}]
});
Run Code Online (Sandbox Code Playgroud)
哪会返回这样的文件:
{
"_id" : ObjectId("539d0756f0ccd69ac5dd61fa"),
"diferencaVencPerd" : 0,
"empateNaoExato" : 0,
"golPerdedor" : 0,
"golVencedor" : 1,
"placarExato" : 2,
"pontos" : 78,
"resumo" : [
{
"partida" : ObjectId("5387d991d69197902ae27586"),
"_id" : ObjectId("539d07eb06b1e60000c19c18"),
"palpite" : [
2,
0
]
},
{
"partida" : ObjectId("5387da7b27f54fb425502918"),
"quesito" : "golsVencedor",
"_id" : ObjectId("539d07eb06b1e60000c19c1a"),
"palpite" : [
3,
0
]
},
{
"partida" : ObjectId("5387dc012752ff402a0a7882"),
"quesito" : "timeVencedor",
"_id" : ObjectId("539d07eb06b1e60000c19c1c"),
"palpite" : [
2,
1
]
},
{
"partida" : ObjectId("5387dc112752ff402a0a7883"),
"_id" : ObjectId("539d07eb06b1e60000c19c1e"),
"palpite" : [
1,
1
]
},
{
"partida" : ObjectId("53880ea52752ff402a0a7886"),
"quesito" : "placarExato",
"_id" : ObjectId("539d07eb06b1e60000c19c20"),
"palpite" : [
1,
2
]
},
{
"partida" : ObjectId("53880eae2752ff402a0a7887"),
"quesito" : "placarExato",
"_id" : ObjectId("539d0aa82fb219000054c84f"),
"palpite" : [
2,
1
]
}
],
"timeVencedor" : 1,
"userId" : ObjectId("539b2f2930de100000d7356c")
}
Run Code Online (Sandbox Code Playgroud)
我的问题是,首先:如何通过quesito过滤resumo嵌套文档?是否可以对此结果进行分页,因为此数组将会增加.最后一个问题,对于这种情况,这是一个很好的方法吗?
感谢你们 !
如上所述,即使您正在存储外部引用,您的架构也意味着您实际上已经嵌入了数据.因此,目前尚不清楚您是同时进行嵌入和引用还是仅仅嵌入.
这里最大的警告是匹配"文档"和实际过滤数组内容之间的区别.既然你似乎在谈论"分页"你的数组结果,那么这里的重点是做到这一点,但仍然提到警告.
数组中的多个"已过滤"匹配需要聚合框架.您通常可以"投影"数组元素的单个匹配,但是在您期望多个匹配时需要这样做:
Ranking.aggregate(
[
// This match finds "documents" that "contain" the match
{ "$match": { "resumo.quesito": "value" } },
// Unwind de-normalizes arrays as documents
{ "$unwind": "$resumo" },
// This match actually filters those document matches
{ "$match": { "resumo.quesito": "value" } },
// Skip and limit for paging, which really only makes sense on single
// document matches
{ "$skip": 0 },
{ "$limit": 2 },
// Return as an array in the original document if you really want
{ "$group": {
"_id": "$_id",
"otherField": { "$first": "$otherField" },
"resumo": { "$push": "$resumo" }
}}
],
function(err,results) {
}
)
Run Code Online (Sandbox Code Playgroud)
或者通过$project使用$map运算符"过滤"MongoDB 2.6方式.但是你仍然需要"寻找$unwind"数组位置,但是由于数组首先被"过滤",所以可能会有更少的处理:
Ranking.aggregate(
[
// This match finds "documents" that "contain" the match
{ "$match": { "resumo.quesito": "value" } },
// Filter with $map
{ "$project": {
"otherField": 1,
"resumo": {
"$setDifference": [
{
"$map": {
"input": "$resumo",
"as": "el",
"in": { "$eq": ["$$el.questio", "value" ] }
}
},
[false]
]
}
}},
// Unwind de-normalizes arrays as documents
{ "$unwind": "$resumo" },
// Skip and limit for paging, which really only makes sense on single
// document matches
{ "$skip": 0 },
{ "$limit": 2 },
// Return as an array in the original document if you really want
{ "$group": {
"_id": "$_id",
"otherField": { "$first": "$otherField" },
"resumo": { "$push": "$resumo" }
}}
],
function(err,results) {
}
)
Run Code Online (Sandbox Code Playgroud)
当你处理单个文档并且只是"过滤"和"分页"数组时,内部使用$skip和$limit这里真正有用.可以使用多个文档执行此操作,但由于无法"切片"数组,因此非常复杂.这将我们带到下一点.
对于嵌入式阵列,对于不需要任何过滤的分页,您只需使用$slice专为此目的而设计的运算符:
Ranking.find({},{ "resumo": { "$slice": [0,2] } },function(err,docs) {
});
Run Code Online (Sandbox Code Playgroud)
您的备用方法是简单地引用外部集合中的文档,然后将参数传递给mongoose .populate()以过滤并"分页"结果.架构本身的变化只是:
"resumo": [{ "type": "Schema.Types.ObjectId", "ref": "Partida" }]
Run Code Online (Sandbox Code Playgroud)
现在,外部引用的集合保持对象细节而不是直接嵌入到数组中.使用.populate()过滤和分页是:
Ranking.find().populate({
"path": "resumo",
"match": { "questio": "value" },
"options": { "skip": 0, "limit": 2 }
}).exec(function(err,docs) {
docs = docs.filter(function(doc) {
return docs.comments.length;
});
});
Run Code Online (Sandbox Code Playgroud)
当然可能存在的问题是,您现在无法再查询包含"嵌入"信息的文档,因为它现在位于另一个集合中.这导致拉入所有文档,尽管可能是通过某些其他查询条件,但随后手动测试它们以查看它们是否被发送以检索这些项目的筛选查询"填充".
所以它确实取决于你在做什么以及你的方法是什么.如果您经常打算在内部数组上"搜索",那么嵌入通常会更适合您.此外,如果您真的只对"分页"感兴趣,那么$slice运算符就可以很好地用于嵌入式文档.但要注意增长嵌入式阵列太大.
使用带有mongoose的引用模式有助于解决一些大小问题,并且有一些方法可以帮助"分页"结果并过滤它们.缺点是你不能再从父本身那里查询那些元素.因此,内部元素的父选择不适合这里.还要记住,虽然并非所有数据都是嵌入的,但仍然存在_id对外部文档值的引用.所以你仍然可以得到大型数组,这可能是不可取的.
对于任何大的东西,考虑一下你可能会自己做这项工作,然后从"孩子"项目向后工作,然后匹配父母.
| 归档时间: |
|
| 查看次数: |
4204 次 |
| 最近记录: |