Get the 2 alphabetically first documents by type

£可爱£侵袭症+ 提交于 2019-12-12 14:04:34

问题


Lets say I have the following collection structure:

{type: 1, value: "f"},
{type: 2, value: "c"},
{type: 2, value: "b"},
{type: 1, value: "d"},
{type: 1, value: "e"},
{type: 2, value: "a"}

Now I want to get the 2 alphabetically first documents ("value") for each "type", the result should look like:

{type: 1, value: "d"},
{type: 1, value: "e"},
{type: 2, value: "a"},
{type: 2, value: "b"},

With MongoDB I have to retrieve all documents and drop the unnecessary ones.

Is there another NoSQL system which has a built-in function to do that?

Another neat requirement would be the possibility to simply update a more than 2-dimensionally nested document, which also isn't possible in MongoDB, since you can only use the positional operator "$" once (see https://jira.mongodb.org/browse/SERVER-831). I need at least 3-dimensional documents, I already have thought that through, everything else would mean a huge performance decrease when reading.

Or are there possibilities to do that in MongoDB I am missing?

I am working with golang, so there should be a well-maintained package for the DB system.


回答1:


To do this you need to sort your documents by value in ascending order using the $sort operator and then $group them by _id and use the $push operator to return array of "values". From there and since aggregation result is an array you can you can use the .map() method which returns array of "key/values" where key is type and values array of first two elements in values ( return by .splice() or .slice() )

db.collection.aggregate([
    { "$sort": { "value": 1 }}, 
    { "$group": { "_id": "$type", "values": { "$push": "$value" }}}
]).map( function( doc ) { 
          return { "type": doc._id, "values": doc.values.splice(0, 2) }})

Output

 [
     {
         "type" : 1,
         "values" : [ "d", "e" ]
     },
     {
         "type" : 2,
         "values" : [ "a", "b" ]
     }
]

Starting from MongoDB 3.2 you can use the $slice operator in your $project stage.

db.collection.aggregate([
    { "$sort": { "value": 1 }}, 
    { "$group": { "_id": "$type", "values": { "$push": "$value" }}},
    { "$project": { "values": { "$slice": [ "$values", 0, 2 ] }}}
])



回答2:


Graph databases may be a nice alternative to MongoDB, as they are more suitable for relationships modeling. You do not have to repeat a type in every document, you can make a node out of it.

Depending on a way you model your data, the task you are asking about may be simpler or more difficult. Not sure if there is a chance of built-in out-of-the box solution, but in worst case you may simply chain your values as nodes connected by relations, maintaining some kind of sorted list of values for each type, which will make getting N-top values for each type easy (and you won't have to retrieve unnecessary data).

There is a library for Neo4j that supports Go, but not sure if it is mature...

When it comes to MongoDB, you may also try to experiment with its own aggregation capabilities. I'm not that much familiar with it, but it seems to be a little bit hard, as $group aggregation has limited number of possible accumulators (you would probably need to apply limit to $push, but it does not seem to be possible)...



来源:https://stackoverflow.com/questions/31940862/get-the-2-alphabetically-first-documents-by-type

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!