在MongoDB中给出以下用户对象,
什么是relation.$.status == 'friends'
搜索的最快方式?
需要在find
集合的user
数据中找到relation
的方法,其中包含值为"friends"
的对象(请参阅下面的伪查询)。
此特定集合的键已设置为uids,因此假设下面的“用户数据”部分可能不会更改。
用户数据:
{
"_id": ObjectId('1a1a1a1a111a1a11a1a1a1a'),
"name": "Tester",
"relation": {
"2b2b2b2b2b2b2b2b2b2b2b": {
"status": 'friends',
"status_changed_date: ISODate("2013-10-28T00:00:00.0000Z"),
// etc...
},
"3c3c3c3c3c3c3c3c3c3c3c": {
"status": 'engaged',
"status_changed_date: ISODate("2013-10-28T00:00:00.0000Z"),
// etc...
}
}
}
查询:
var query = {
// pseudo, key-ignoring nested document search
'relation.$.status': 'friends'
}
var projection = {
'relation': 1
}
db.user.findOne(query, projection)
期望输出:
{
"2b2b2b2b2b2b2b2b2b2b2b": {
"status": 'friends',
"status_changed_date: ISODate("2013-10-28T00:00:00.0000Z"),
// etc...
}
}
对用户数据结构的明显更正应该是使relation
一个对象数组包含_id
和status
作为键。有点在这里寻找一个临时的垫片。
答案 0 :(得分:1)
您可以将mongodb Map/Reduce技术应用于此任务。
1) map
函数将确定来自relation
对象的嵌套对象,其中status
字段等于"friends"
值:
var map = function () {
for (var key in this.relation) {
var relation = this.relation[key];
if (relation.status == "friends")
emit(key, relation);
}
}
2) reduce
函数实际上什么都不做,只返回单个发出的关系:
var reduce = function (key, values) {
return values[0];
}
因此,您将拥有包含此类对象的集合:
{
_id: "2b2b2b2b2b2b2b2b2b2b2b",
value: {
status: "friends",
status_changed_date: ISODate("2013-10-28T00:00:00.0000Z"),
// etc...
}
}
如果您决定将relation
对象替换为数组,则可以使用aggregation framework构建类似的查询。
用户数据:
{
_id: ObjectId("1a1a1a1a111a1a11a1a1a1a"),
name: "Tester",
relations: [
{
id: "2b2b2b2b2b2b2b2b2b2b2b",
status: "friends",
status_changed_date: ISODate("2013-10-28T00:00:00.0000Z"),
// etc...
},
{
id: "3c3c3c3c3c3c3c3c3c3c3c",
status: "engaged",
status_changed_date: ISODate("2013-10-28T00:00:00.0000Z"),
// etc...
}
]
}
<强>查询:强>
db.collection.aggregate([
{ $unwind: "$relations" },
{ $match: { "relations.status": "friends" } },
{ $project: _id: 0,
id: "$relations.id",
status: "$relations.status",
status_changed_date: "$relations.status_chaged_date"
// etc...
}
])
<强>输出:强>
{
id: "2b2b2b2b2b2b2b2b2b2b2b",
status: "friends",
status_changed_date: ISODate("2013-10-28T00:00:00.0000Z"),
// etc...
}