MongoDB中的嵌套文档值搜索

时间:2013-10-29 18:40:27

标签: mongodb nested document

在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一个对象数组包含_idstatus作为键。有点在这里寻找一个临时的垫片。

1 个答案:

答案 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...
}