数据&问题
鉴于赛马会议的集合(db.sectionals
),如何编写查询以便返回position: [2]
?
[
{
"race": {
"date": ["2013-05-08"],
"meeting": ["canterbury park"],
"weather": ["fine"],
"field": {
"Belladini": {
"position": [2],
"distance": [1100]
},
"Bobs Destiny": {
"position": [7],
"distance": [1100]
}
}
}
},
{
"race": {
"date": ["2013-03-27"],
"meeting": ["canterbury park"],
"weather": ["fine"],
"field": {
"Berna": {
"position": [5],
"distance": [1550]
},
"Excited Prince": {
"position": [2],
"distance": [1550]
}
}
}
}
]
期望的结果
在这个例子中,我希望它返回类似
的东西 "Belladini": {
"position": [2],
"distance": [1100]
},
"Excited Prince": {
"position": [2],
"distance": [1550]
}
尝试
我在嵌套数组上找到了the documentation,发现数组元素有点令人困惑,并尝试了各种尝试,例如
db.Sectionals.find({ "race.field.position": 2} )
db.Sectionals.find({ "race.field": { $elemMatch: { position: 2} } } )
db.Sectionals.find({ "race.field": {$all: [{"position": 2}] }} )
没有成功。
其他信息
我正在使用Robomongo。
答案 0 :(得分:3)
这里出错的地方在于您的文档设计。请看以下部分:
"field": {
"Berna": {
"position": [5],
"distance": [1550]
},
"Excited Prince": {
"position": [2],
"distance": [1550]
}
}
不要问为什么你会想要内在的元素,比如" position"和"距离"无论如何要成为阵列,这里的关键问题是" field"不是数组。你没有使用数组,而是使用了"对象键"识别不同类型的数据。
您需要了解的是,对于数据库"这是非常糟糕的做法。你的"键"例如" Berna"和#34;兴奋的王子"包含您可以查询的有用数据。但是现在,你不能这样做,因为"键名"而不是"价值观"在数据文件中。数据库实际上只关注"值",特别是当涉及"索引"内容。
所以得到" Horses"现在是不可能的,没有导致代码迭代所有对象键并提取" Horses"。使用mapReduce操作可以做到这一点,但是对于仅提取项目肯定有点过分,而且效率不高。
基本查询参数也不可能,因为现在您必须执行以下操作:
{ "race.field.Excited Prince.position": 2 }
哪个会让你排在第二位?#34;兴奋的王子",但要测试所有"马匹"你基本上需要指定每个可能的关键路径。没有通配符可用于键名,任何条件都会再次返回到JavaScript编码和遍历对象。
总而言之,像你这样的建模是一个“不好的”#34;实践。它不具备性能,缺乏灵活性并且充满问题。
所以至少将结构更改为这样的数组:
"field": [
{
"Horse": "Berna",
"position": [5],
"distance": [1550]
},
{
"Horse": "Excited Prince",
"position": [2],
"distance": [1550]
}
]
现在您可以基本上查询和匹配文档:
db.Sectionals.find({ "race.field.position": 2 })
至少匹配所有文件。
或者针对您的具体投影,请使用.aggregate()
:
db.Sectionals.aggregate([
{ "$match": {
"race.field.position": 2
}},
{ "$unwind": "$race.field" },
{ "$match": {
"race.field.position": 2
}},
{ "$project": {
"Horse": "$race.field.Horse",
"position": "$race.field.position",
"distance": "$race.field.distance"
}}
])
返回:
{
"_id" : ObjectId("55e161545c6a4540fa687037"),
"Horse" : "Belladini",
"position" : [
2
],
"distance" : [
1100
]
}
{
"_id" : ObjectId("55e161545c6a4540fa687038"),
"Horse" : "Excited Prince",
"position" : [
2
],
"distance" : [
1550
]
}
答案 1 :(得分:2)
您需要更改文档结构的更改,最好的方法是使用"Bulk"操作。
var bulk = db.sectionals.initializeOrderedBulkOp(),
count = 0;
db.sectionals.find().forEach(function(doc){
var field = doc.race['field'];
var newField = [];
for (var key in field ){
newField.push({
'Horse': key,
'position': field[key]['position'],
'distance': field[key]['distance']
});
}
bulk.find({ "_id": doc._id }).update({
"$set": { "race.field": newField }
});
count++;
if (count % 500 == 0) {
bulk.execute();
bulk = db.sectionals.initializeOrderedBulkOp();
}
})
if (count % 500 != 0)
bulk.execute();
您的文档如下所示:
{
"_id" : ObjectId("55e16462d4a8842b9fd90bfa"),
"race" : {
"date" : [
"2013-05-08"
],
"meeting" : [
"canterbury park"
],
"weather" : [
"fine"
],
"field" : [
{
"Horse" : "Belladini",
"position" : [
2
],
"distance" : [
1100
]
},
{
"Horse" : "Bobs Destiny",
"position" : [
7
],
"distance" : [
1100
]
}
]
}
}
然后你可以使用聚合,因为@BlakesSeven已在他的回答中提及。
db.sectionals.aggregate([
{ "$match": {
"race.field.position": 2
}},
{ "$unwind": "$race.field" },
{ "$match": {
"race.field.position": 2
}},
{ "$project": {
"Horse": "$race.field.Horse",
"position": "$race.field.position",
"distance": "$race.field.distance"
}}
])
{ "_id" : ObjectId("55e16462d4a8842b9fd90bfa"), "Horse" : "Belladini", "position" : [ 2 ], "distance" : [ 1100 ] }
{ "_id" : ObjectId("55e16462d4a8842b9fd90bfb"), "Horse" : "Excited Prince", "position" : [ 2 ], "distance" : [ 1550 ] }