0

我有一个名为“元素”的集合,用于存储课程和曲目。课程和曲目使用名为 cms_content_type 的字段进行区分,该字段对于课程来说是“课程”,对于曲目来说是“曲目”。有一个 cms_id 字段可以唯一标识一个元素,无论是曲目还是课程。轨道由 track_lessons 字段中的一个或多个课程组成。

课程文档的结构是:

{
    '_id': ObjectId('1234'),
    'name': 'Working with Tags',
    'cms_content_type': 'Lesson',
    'cms_id': 'abcd1234'
}

跟踪文件的结构是:

{
    '_id': ObjectId('4567'),
    'name': 'Tags 101',
    'cms_content_type': 'Track',
    'cms_id': 'pqrs4567'
    'track_lessons':[
        {'lesson_cms_id': 'efgh1234'},
        {'lesson_cms_id': 'jklm1234'}
    ]
}

我想查询此元素集合以获取任何轨道中不存在的课程列表。我怎样才能做到这一点?我是 MapReduce 的新手。我必须使用它来获取此列表吗?

另一个要求是我应该能够对检索到的课程列表进行排序和分页。因此,我更愿意编写动态查询,而不是将结果存储在单独的集合中并进行处理。

非常感谢任何帮助。

4

2 回答 2

0

我怀疑 M/R 在这里有什么帮助。因为在您当前的设计中,您需要从一个集合中检查另一个集合(即课程和曲目)中的一些 id。在 M/R 中,您不能从 map reduce 函数运行 db 查询。当前的设计正在打破数据局部性,并且在外键使用方面倾向于更像关系型。因此,您需要为查询的性能(某种连接)付费。Derick 的解决方案试图通过在每个文档中包含所需的信息来克服这个局部性问题。我完全鼓励您将所需的数据放入一个文档中。

如果您必须使用当前的设计,直接的解决方案是:

var lessons_without_task = [];
db.lessons.find().forEach(
   function(lesson_doc) {
      var task = db.tasks.findOne({ "track_lessons.lesson_cms_id" : lesson_doc.cms_id });
      if (task == null) {
        lessons_without_task.push(lesson_doc.cms_id);
      }
   }
)

我在这里假设您在track_lessons.lesson_cms_id. 请参阅http://docs.mongodb.org/manual/core/indexes/#index-type-multi-key 您可能需要为大型集合添加以下选项(紧随其后find()
addOption(DBQuery.Option.awaitData).addOption(DBQuery.Option.noTimeout)

于 2013-07-09T21:56:30.533 回答
0

我想查询此元素集合以获取任何轨道中不存在的课程列表。我怎样才能做到这一点?

您不能使用 M/R,因为它仅适用于一个集合。重新设计架构是您当然想要阻止的事情,但现在您的架构不足以满足您的需求。在 MongoDB 中,您根据使用数据的方式设计模式,这与根据规范化规则设计模式的 RDBM 不同

因此,到目前为止,最简单的方法是将轨道的 存储为包含课程文档cms_id的数组:

{
    '_id': ObjectId('1234'),
    'name': 'Working with Tags',
    'cms_content_type': 'Lesson',
    'cms_id': 'abcd1234',
    'tracks': [ 'pqrs4567' ]
}

这样,您无需进行繁琐的 M/R 查询,并且可以像以下方式一样轻松地查询它们:

db.col.find( { tracks: { $size: 0 } );

您也不应该将它们存储为嵌套数组,就像您在相反的方向上所做的那样,而是只存储 ID:

{
    '_id': ObjectId('4567'),
    'name': 'Tags 101',
    'cms_content_type': 'Track',
    'cms_id': 'pqrs4567'
    'track_lessons': [ 'efgh1234', 'jklm1234' ]
}

如果您在 track_lessons(或轨道)上创建索引,这会使事情变得更加优化。但我建议您完全离开 track_lessons 并将轨道与课程一起存储:

{
    '_id': ObjectId('1234'),
    'name': 'Working with Tags',
    'cms_content_type': 'Lesson',
    'cms_id': 'abcd1234',
    'tracks': [ 'pqrs4567' ]
}
{
    '_id': ObjectId('4567'),
    'name': 'Tags 101',
    'cms_content_type': 'Track',
    'cms_id': 'pqrs4567'
}

即使您不存储属于轨道的所有课程(例如标签 101),您仍然可以使用以下查询轻松查询属于轨道的所有课程:

db.col.find( { tracks: 'pqrs4567' } );

通过进行这些更改,您可以完全忘记 M/R,这使您的应用程序更易于维护和更快。

于 2013-07-09T17:08:14.303 回答