Sort Sub Documents in MongoDB

后端 未结 5 1247
北恋
北恋 2020-12-17 14:52

Is there a way to sort sub documents in a mongo query?

For example:

{
  \"_id\" : ObjectId(\"4c69d19532f73ad544000001\"),
  \"content\" : \"blah bla         


        
相关标签:
5条回答
  • 2020-12-17 15:13

    It's not possible directly out of MongoDB, however when you pull the document you can then sort the array as if it was an array of objects, using whatever native sort method your language has. This is how I do comments on my blog with MongoDB.

    PHP Code

    /* Takes an array of comments and turns them into native objects */
    public static function loadMany($pcomments)
    {
        $comments = array();
        if(isset($pcomments) && count($pcomments) > 0)
        {
            foreach($pcomments as $key => $comment)
            {
                $comment['data']['index'] = $key;
                $comments[] = Comment::loadOne($comment['data']);
            }
        }
        usort($comments, "comment_compare");
        return $comments;
    }
    
    /* Compares comment timestamps */
    function comment_compare($a, $b)
    {
        if($a->timestamp->sec == $b->timestamp->sec)
        {
            return 0;
        }
        return ($a->timestamp->sec < $b->timestamp->sec) ? -1 : 1;
    }
    
    0 讨论(0)
  • 2020-12-17 15:14

    In mongo version 2.4 or above, you can use $sort while updating. The new modifier let you sort sub document.

    More information could read this page, http://docs.mongodb.org/manual/reference/operator/sort/

    0 讨论(0)
  • 2020-12-17 15:16

    I dont think you can. I raised same question on the forums.

    0 讨论(0)
  • 2020-12-17 15:17

    Starting in Mongo 4.4, the $function aggregation operator allows applying a custom javascript function to implement behaviour not supported by the MongoDB Query Language.

    For instance, in order to sort an array of objects by one of their fields:

    // {
    //   "content": "blah blah blah",
    //   "comments": [
    //     { "author": "jim", "content": "comment content 1", "date": "07-24-1995" },
    //     { "author": "joe", "content": "comment content 2", "date": "07-24-1996" },
    //     { "author": "amy", "content": "comment content 3", "date": "09-10-1999" }
    //   ]
    // }
    db.collection.aggregate(
      { $sort: { content: 1 } }, // or whatever sort order
      { $set:
        { "comments":
          { $function: {
              body: function(comments) {
                return comments.sort((a, b) => a.date < b.date);
              },
              args: ["$comments"],
              lang: "js"
          }}
        }
      }
    )
    // {
    //   "content": "blah blah blah",
    //   "comments": [
    //     { "author": "amy", "content": "comment content 3", "date": "09-10-1999" },
    //     { "author": "joe", "content": "comment content 2", "date": "07-24-1996" },
    //     { "author": "jim", "content": "comment content 1", "date": "07-24-1995" }
    //   ]
    // }
    

    $function takes 3 parameters:

    • body, which is the function to apply, whose parameter is the array to modify.
    • args, which contains the fields from the record that the body function takes as parameter. In our case "$comments".
    • lang, which is the language in which the body function is written. Only js is currently available.
    0 讨论(0)
  • 2020-12-17 15:19

    It is possible when use in sequence $unwind > $sort > $group specialty for array,

    • $unwind deconstruct array comments
    db.collection.aggregate([
      { $unwind: "$comments" },
    
    • $addFields to add new field for date, field is in string and we need to convert it to an ISO date for proper sorting, to convert string date to ISO date use $dateFromString
      {
        $addFields: {
          "comments.dateISO": {
            $dateFromString: {
              dateString: "$comments.date",
              format: "%m-%d-%Y"
            }
          }
        }
      },
    
    • $sort comments.dateISO in descending (-1) order
      { $sort: { "comments.dateISO": -1 } },
    
    • $group by _id, and re-construct comments array using $push objects and other fields remain using $first
      {
        $group: {
          _id: "$_id",
          comment: { $first: "$comment" },
          comments: { $push: "$comments" }
        }
      }
    ])
    

    Playground

    0 讨论(0)
提交回复
热议问题