我从MongoDb和nodejs开始(使用mongoose)。
我有故事的集合,每个人都可以有一个或多个标签,就像这样:
{
title: "The red fox",
content: "The red fox jumps away...",
tags: [
{
tagname: "fairytale",
user: "pippo"
},
{
tagname: "funny",
user: "pluto"
},
{
tagname: "fox",
user: "paperino"
}
]
},
... other stories
现在我想制作一个标签云。
这意味着查询所有标签的故事。
在关系世界(例如MySQL)中,我会有一个Stories表,一个Tags表和一个Stories_Tags表(多对多)。然后我会在标签表或类似的东西上查询。
有没有办法这样做? (我确定是的)
如果是,这是一个好习惯吗?还是打破了nosql范式呢?
你能为我的架构设计想象一个更好的方法吗?
答案 0 :(得分:10)
以下是使用聚合框架执行此操作的方法(您需要使用刚刚发布的2.2)。
db.stories.aggregate(
[
{
"$unwind" : "$tags"
},
{
"$group" : {
"_id" : "$tags.tagname",
"total" : {
"$sum" : 1
}
}
},
{
"$sort" : {
"total" : -1
}
}
])
您的结果将如下所示:
{
"result" : [
{
"_id" : "fairytale",
"total" : 3
},
{
"_id" : "funny",
"total" : 2
},
{
"_id" : "silly",
"total" : 1
},
{
"_id" : "fox",
"total" : 1
}
],
"ok" : 1
}
答案 1 :(得分:2)
欢迎来到Mongo
您的数据的最佳“架构”将是这样的。
您创建了一个名为stories的集合,每个故事都将成为此集合中的一个文档。 然后,您可以使用类似的方式轻松查询数据。
db.stories.find({ "tags.tagname": "fairytale"}); // will find all documents that have fairytale as a tagname.
<强>更新强>
db.stories.find({ "tags.tagname": { $exists : true }}); // will find all documents that have a tagname.
注意查找查询中的点表示法,就是你如何进入mongo中的数组/对象。
答案 2 :(得分:2)
您可以使用MR来完成此任务。在MR中,您只需选择标签并进行投影:
var map = function(){
for(var i=0;i<this.tags.length;i++){
emit(this.tags[i].tagname, {count: 1});
}
}
然后你的减少将通过发出的文件运行,基本上总结了标签被看到的次数。
如果升级到最新的不稳定2.2,您也可以使用聚合框架。您可以使用聚合框架的$ project和$ sum piplines来标记每个帖子中的标记,然后将它们相加以创建基于分数的标记云,允许您根据求和来调整每个标记的文本大小。
如果是,这是一个好习惯吗?还是打破了nosql范式呢?
这是MongoDB中一个非常标准的问题,你不会逃避。使用可重用的结构,不可避免地需要对它进行一些复杂的查询。幸运的是,在2.2中有一个要保存的聚合框架。
至于这是好的还是坏的方法,它是一个非常标准的方法,因为它既不好也不坏。
为了使结构更好,您可以将具有计数的唯一标记预先聚合到单独的集合中。这样可以更轻松地实时构建标签云。
预聚合是一种创建通常从MR获得的其他集合的形式,无需使用MR或聚合框架。它通常是基于您的应用程序的事件,因此当用户创建帖子或重新发布帖子时,它将触发预先聚合事件到“tag_count”的集合,如下所示:
{
_id: {},
tagname: "",
count: 1
}
当事件被触发时,你的应用程序将遍历帖子上的标签,基本上是这样做$ inc upsert:
db.tag_count.update({tagname: 'whoop'}, {$inc: {count: 1}}, true);
因此,您现在将在整个博客中拥有一系列标记。从那里你走与MR一样的路线,只是查询这个集合来获取你的数据。你当然需要处理删除和更新事件,但你会得到一般的想法。
答案 3 :(得分:0)
嗯,有不同的方法。我认为您的解决方案与this one之间没有区别。
此外,您还可以将其map_reduce方法复制并粘贴到输出标记计数哈希。