用猫鼬查询嵌套文档
Query nested document with 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
}]
});
返回如下文档:
{
"_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")
}
我的问题是,首先:我如何通过问卷过滤简历嵌套文档?是否有可能对这个结果分页,因为这个数组将会增加。最后一个问题,这是处理这种情况的好方法吗?
如前所述,您的模式意味着您实际上已经嵌入了数据,即使您正在存储外部引用。因此,不清楚您是在做嵌入和引用还是简单地嵌入本身。
这里需要注意的是匹配"文档"和实际过滤数组内容之间的区别。由于您似乎在谈论"分页"您的数组结果,因此这里的重点是如何做到这一点,但仍然提到了警告。
数组中的多个"过滤"匹配需要聚合框架。您通常可以"投影"数组元素的单个匹配项,但在您希望有多个匹配项时需要这样做:
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) {
}
)
或MongoDB 2.6的方式"过滤"内部的 $project
使用 $map
操作符。但是仍然需要 $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) {
}
)
$skip
和 $limit
的内部用法只有在处理单个文档并且只是"过滤"answers"分页"数组时才有意义。可以对多个文档执行此操作,但是非常复杂,因为没有办法只"切片"数组。这就引出了下一个问题。
对于嵌入式数组,对于不需要任何过滤的分页,您只需使用 $slice
操作符,这是为此目的而设计的:
Ranking.find({},{ "resumo": { "$slice": [0,2] } },function(err,docs) {
});
您的替代方法是简单地引用外部集合中的文档,然后将参数传递给mongoose .populate()
以过滤和"页面"结果。模式本身的更改只需:
"resumo": [{ "type": "Schema.Types.ObjectId", "ref": "Partida" }]
外部引用集合现在保存对象细节,而不是直接嵌入到数组中。.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;
});
});
当然,可能存在的问题是,您不再能够实际查询包含"嵌入"信息的文档,因为它现在在另一个集合中。这将导致拉入所有文档,尽管可能通过一些其他查询条件,但随后手动测试它们,以查看它们是否被发送来检索这些项的过滤查询"填充"。
所以这真的取决于你在做什么和你的方法是什么。如果您经常打算在内部数组上"搜索",那么嵌入通常更适合您。此外,如果您真的只对"分页"感兴趣,那么 $slice
操作符可以很好地用于嵌入式文档的此目的。但是要小心嵌入数组太大。
在mongoose中使用引用模式有助于解决一些大小问题,并且有一种方法可以帮助"分页"结果并对其进行过滤。缺点是您不能再从父元素本身查询这些元素的"内部"。所以内部元素的父选择在这里不太合适。还要记住,虽然不是所有的数据都被嵌入,但是仍然有对外部文档的_id
值的引用。因此,您仍然可以使用大数组,这可能不是理想的。
对于任何大的元素,请考虑您可能自己完成工作,并从"子"项向后工作,然后匹配父项。
我不确定您是否可以直接使用mongoose过滤子文档。然而,你可以用Model.find({'resumo.quesito': 'THEVALUE'})
获得父文档(你也应该在它上面有一个索引)
当你有了父母你可以通过比较问卷得到孩子
更多文档可以在这里找到:http://mongoosejs.com/docs/subdocs.html
- Mongoose查询嵌套文档的时间或多或少为某个日期
- HTML5从嵌套iframe内部调整顶级文档iframe的大小
- Mongodb 嵌套文档更新
- 嵌套文档.writes和第三方广告在IE中不起作用!!!!任何安全的解决方法
- jQuery - 单击包含
- 下拉菜单的嵌套文本字段悬停
- Expressjs Mongoose 查找嵌套的嵌入式文档未定义
- 添加到猫鼬嵌套文档
- 过滤 meteorjs 中的嵌套文档
- 使用虚拟属性访问猫鼬模型中的嵌套文档
- 在MongoDB中插入/向上插入嵌套文档
- Node.js/Mongoose - 过滤嵌套文档
- Meteor:更新文档数组中的嵌套对象
- 将嵌套文档集合转换为具有父引用的模型树结构
- 使用MongoDB查询JSON中的嵌套文档
- Fields_for with mongoid embeds_many嵌套文档
- 嵌套文档评估搜索
- 传递嵌套文档查询字段
- 获取警报中最后一个嵌套文本字段的值
- 当嵌套文档存在时,如何验证该嵌套文档的属性是否存在
- 用猫鼬查询嵌套文档