2

I have document called question

var QuestionSchema = new Schema({
    title: {
        type: String,
        default: '',
        trim: true
    },
    body: {
        type: String,
        default: '',
        trim: true
    },
    user: {
        type: Schema.ObjectId,
        ref: 'User'
    },
    category: [],
    comments: [{
        body: {
            type: String,
            default: ''
        },
        root: {
            type: String,
            default: ''
        },
        user: {
            type: Schema.Types.ObjectId,
            ref: 'User'
        },
        createdAt: {
            type: Date,
            default: Date.now
        }
    }],
    tags: {
        type: [],
        get: getTags,
        set: setTags
    },
    image: {
        cdnUri: String,
        files: []
    },
    createdAt: {
        type: Date,
        default: Date.now
    }
});

As a result, I need to sort comments by root field, like this example

I tried to sort the array of comments manually at backend and tried to use aggregation, but I was not able to sort this. Help please.

1
  • 2
    Can you please edit your question to show us what you have tried so far, in terms of the aggregation pipeline that you mentioned and can you include the actual code of what your expected output is rather than embedding links as we would like to reproduce the same problem and help you solve it. Commented Jun 25, 2015 at 11:07

1 Answer 1

3

Presuming that Question is a model object in your code and that of course you want to sort your "comments by "date" from createdAt then using .aggregate() you would use this:

Question.aggregate([
    // Ideally match the document you want
    { "$match": { "_id": docId } },

    // Unwind the array contents
    { "$unwind": "comments" },

    // Then sort on the array contents per document
    { "$sort": { "_id": 1, "comments.createdAt": 1 } },

    // Then group back the structure
    { "$group": {
        "_id": "$_id",
        "title": { "$first": "$title" },
        "body": { "$first": "$body" },
        "user": { "$first": "$user" },
        "comments": { "$push": "$comments" },
        "tags": { "$first": "$tags" },
        "image": { "$first": "$image" },
        "createdAt": { "$first": "$createdAt" }
    }}
],
function(err,results) {
    // do something with sorted results
});

But that is really overkill since you are not "aggregating" between documents. Just use the JavaScript methods instead. Such as .sort():

Quesion.findOneById(docId,function(err,doc) {
    if (err) throw (err);
    var mydoc = doc.toObject();
    mydoc.questions = mydoc.questions.sort(function(a,b) {
        return a.createdAt > b.createdAt;
    });
   console.log( JSON.stringify( doc, undefined, 2 ) ); // Intented nicely
});

So whilst MongoDB does have the "tools" to do this on the server, it makes the most sense to do this in client code when you retrieve the data unless you actually need to "aggregate" accross documents.

But both example usages have been given now.

Sign up to request clarification or add additional context in comments.

3 Comments

+1 for the "do it in the client" or at least not in Mongo. You should use aggregation when you want to deal with several documents, e.g get the 100 last comments on your website
@stephane-ruhlmann Yes that is the point here so many thanks for getting it. Too many people think the "NoSQL" way is just an extension of the "bad habbits" they already picked up from the "SQL way". In fact it was never the way they "should be doing it" even with an RDBMS where that did actuallly suit ( or not ) their purposes.Just trying to point to what is right and as you say "in the client" appears to be the correct case here.
Great summary, nothing to add!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.