Alexander Mills
Alexander Mills

Reputation: 100000

Mongoose - get length of array in model

I have this Mongoose schema:

var postSchema = mongoose.Schema({

    postId: {
        type: Number,
        unique: true
    },

    upvotes: [
        {
            type: Number,
            unique: true
        }
    ]

});

what the best query to use to get the length of the upvotes array? I don't believe I need to use aggregation because I only want to query for one model, just need the length of the upvotes array for a given model.

Really struggling to find this info online - everything I search for mentions the aggregation methodology which I don't believe I need.

Also, as a side note, the unique schema property of the upvotes array doesn't work, perhaps I am doing that wrong.

Upvotes: 15

Views: 28741

Answers (4)

ram
ram

Reputation: 690

postSchema.virtual('upvoteCount').get(function () {
    return this.upvotes.length
});

let doc = await Post.findById('foobar123')

doc.upvoteCount // length of upvotes

Upvotes: 3

Ryan Knell
Ryan Knell

Reputation: 6322

I'm not normally a fan of caching values, but it might be an option (and after finding this stackoverflow answer is what I'm going to do for my use case) to calculate the length of the field when the record is updated in the pre('validate') hook. For example:

var schema = new mongoose.Schema({
    name: String,
    upvoteCount: Number,
    upvotes: [{}]
});

schema.pre('validate', function (next) {
  this.upvoteCount = this.upvotes.length
  next();
});

Just note that you need to do your updates the mongoose way by loading the object using find and then saving changes using object.save() - don't use findOneAndUpdate

Upvotes: 8

prasun
prasun

Reputation: 7343

My suggestion would be to pull the entire upvotes fields data and use .length property of returned array in node.js code

//logic only, not a functional code
post.find( filterexpression, {upvote: 1}, function(err, res){
  console.log(res.upvotes.length); 
});

EDIT:

Other way of doing would be stored Javascript. You can query the upvote and count the same in mongodb side stored Javascript using .length

Upvotes: 2

JohnnyHK
JohnnyHK

Reputation: 311855

find results can only include content from the docs themselves1, while aggregate can project new values that are derived from the doc's content (like an array's length). That's why you need to use aggregate for this, even though you're getting just a single doc.

Post.aggregate([{$match: {postId: 5}}, {$project: {upvotes: {$size: '$upvotes'}}}])

1Single exception is the $meta projection operator to project a $text query result's score.

Upvotes: 20

Related Questions