我需要帮助mongodb中的一些高级集合排序。假设我们有数据库本地,我们有以下模型:
收集大陆的文件 {“_ id”:1,“name”:“Europe”},{“_ id”:2,“name”:“Asia”},{“_ id”:3,“name”:“North America”}, {“_ id”:4,“name”:“South America”},{“_ id”:5,“name”:“Australia”},{“_ id”:6,“name”:“Africa”}
带文件的收集国家/地区 { “_id”:1, “名”: “法国”, “populationInMillions”:66, “大陆”:DBREF( “大陆”,1, “本地”), “城市”:[{ “Name”:“巴黎“},{” 名称 “:” 马赛 “},{” 名称 “:” 图卢兹“}]},
{ “_编码”:2 “名称”: “西班牙”, “populationInMillions”:47, “非洲大陆”:DBREF( “大陆”,1, “本地”), “城市”:[{ “姓名” : “马德里”},{ “名称”: “塞维利亚”},{ “名称”: “巴伦西亚”}]},
{ “_ ID”:3 “名称为”: “中国”, “populationInMillions”:1360, “非洲大陆”:DBREF( “大陆”,2, “本地”), “城市”:[{ “姓名” : “北京”},{ “名称”: “渝”},{ “名称”: “上海”}]},
{ “_编码”:4 “名称”: “巴西”, “populationInMillions”:200, “非洲大陆”:DBREF( “大陆”,4 “本地”), “城市”:[{ “姓名” :“Sao Paulo”},{“name”:“Rio de Janeiro”},{“name”:“Salvador”}}}
因此,当我们想通过一些简单的标准(如populationInMillions降序)对国家进行排序时,我们将使用查询: db.country.find({})。sort({populationInMillions:-1})
我的问题是如果我们想按照以下某些复杂标准进行排序 (本例中的一些在现实世界中有意义,有些没有意义,但重点在于技术解决方案。 我必须在现实世界的项目中应用类似的解决方案。)
排序国家/地区: 1.以他们大陆的名义(考虑到我们没有子对象而是DBRef)
如果您对所有或部分问题有答案,请提供帮助。 提前谢谢!
答案 0 :(得分:2)
从目前存储文档的方式来看,我认为解决方案既昂贵又不可能,因为根据这两个集合的关系添加了更多的排序,尤其是涉及分页时。我建议你把大陆信息放入国家馆藏。 MongoDB被设计为非规范化,更好地利用它。
1 - 按大陆名称排序国家/地区
_id
,您可以使用$in
运营商提取国家/地区列表。HashMap
问题:在这种情况下几乎不可能进行分页。这是低效的,重复的结果是可能的,你不可能自己排序国家,只有大陆和#39;名称可以排序。
2 - 优先排序首先超过1000的国家
我真的不明白你用这个想要实现的目标。按人口计数排序似乎很好地解决了这个问题。但是,如果您需要以下内容:
|----------------|
|populationCount |
|----------------|
|2500 |
|2030 |
|2110 |
|2666 |
|1999 |
|800 |
|600 |
|700 |
|----------------|
为此,您可以在国家/地区集合中添加权重列。对于超过一定数量的populationInMillions
(在您的情况下为1000)的所有国家/地区,请将其设置为更高的权重,其余的则为更低的权重。这样,您可以根据需要使用db.Countries.sort({weight : -1})
或db.Countries.sort({weight : -1, populationInMillions : -1})
对其进行排序。它将是这样的:
|----------------|------|
|populationCount |weight|
|----------------|------|
|2500 |2 |
|2030 |2 |
|2110 |2 |
|2666 |2 |
|1999 |2 |
|800 |1 |
|600 |1 |
|700 |1 |
|----------------|------|
3 - 按所有城市名称中的总字符数排序。
我不认为MongoDB有一种方法可以动态执行该查询,但由于城市名称没有改变,您可以在添加或删除城市时存储总字符数。国家。这样你可以用那个列排序。易于执行和排序可以编制索引。表现友好。
4 - 按字母顺序排列第二个城市的名称。
我不知道这意味着什么。有什么例子吗?
p / s:当需要对某些内容进行排序时,请尝试确保标准位于一个集合中以便于查询。
答案 1 :(得分:1)
我绝对同意在mongodb中应该避免规范化,在上面的例子中我们应该将该大陆作为该国的一个子对象,以便我们可以轻松地对非洲大陆的国家进行过滤和排序。
在上一个答案中,通过向数据模型添加新字段来实现任务有一些很好的建议。在进行了一些mongodb研究后,我发现了另一种实现结果的方法,而没有真正改变数据模型。该解决方案使用聚合。让我们看一下示例2(以人口百万大于1000的国家位于其他国家之前的方式对国家进行排序)。这种类型的解决方案通常可以应用于许多其他自定义排序标准:
db.country.aggregate( [
{ $project:
{ _id: "$_id",
name : "$name",
populationInMillions : "$populationInMillions",
cities : "$cities",
populationRank: { $cond: { if: { $gt : [ "$populationInMillions" , 1000 ] }, then: 0 , else: 1 }}
}
},
{ $sort : {'populationRank' : 1 /*, 'anotherField1' : -1, 'anotherField2' : 1*/} },
{ $project : { /*We can skip this projection if we don't want to exclude populationRank from the result*/
_id : "$_id",
name : "$name",
populationInMillions : "$populationInMillions",
cities : "$cities" }
}
] );
对于示例数字3(按其所有城市名称中的字符总数),我们很遗憾没有$ strlen函数,但它将在未来的mongodb版本中添加。 https://jira.mongodb.org/browse/SERVER-5319 但是如果我们假设我们已经有了$ strlen函数,那么这里是第3个示例的有趣解决方案,它也可以为不依赖strlen的其他自定义排序条件提供一个想法:
db.country.aggregate(
[ { $unwind : "$cities" },
{ $group : {
_id : "$_id",
name : { $max : "$name" },
populationInMillions : { $max : "$populationInMillions" },
cities : { $push : "$cities" },
citiesCharCount : { $sum : { $strlen : "$cities.name" } } } },
{ $sort : { citiesCharCount : 1 } },
{ $project : { /*We can skip this projection if we don't want to exclude citiesCharCount from the result*/
_id : "$_id",
name : "$name",
populationInMillions : "$populationInMillions",
cities : "$cities" }
}
]
);
没有strlen函数,有基于mapResuce和自定义javascript函数的解决方案https://docs.mongodb.com/manual/tutorial/map-reduce-examples/