6

This is very similar to this question, however, when using a similar approach, I keep getting a list of only the documents that contain subdocuments.

I have a simple schema with questions that can be up and down voted. My schema (I removed some fields for simplicity):

var mongoose = require('mongoose');

var voteSchema = new mongoose.Schema({
  value: Number,
});

// Document schema for polls
exports.PollSchema = new mongoose.Schema({
    question: { type: String, required: true },
    votes: [voteSchema],
});

I want to have a list with all questions and their respective score. A score is the sum of the 'value' field in voteSchema.

I'm trying to use $cond to make sure the empty votes document is replaced with at least one vote subdocument with a value of 0. Unfortunately, when using it, all my totalScore fields are 0. If not using it, I get the correct totalScore, but only for the non empty ones.

Poll.aggregate([
    { $project: {
        _id: 1,
        question: 1,
        totalScore : 1,
        votes : { $cond : [ { $eq : ["$votes.length", 0]}, '$votes', [ { value : 0} ]] }
    }},
    { $unwind: "$votes" },
    { $group: {
        _id : "$_id",
        question: { $first: "$question" },
        totalScore : { $sum: "$votes.value" }
    }},
], function(error, polls) {
    console.dir(polls);
});

2 Answers 2

20

If your empty votes is null (not exists), try to use:

{ $ifNull : [ "$votes", [ { value : 0 } ] ] }  

instead of:

{ $cond : [ { $eq : [ "$votes.length", 0 ] }, '$votes', [ { value : 0 } ] ] }  

If your empty votes is [] (empty array):

{ $cond : [ { $eq : [ "$votes", [] ] }, [ { value : 0 } ], '$votes' ] }  

And some about $cond operator:

Its syntax: { $cond: [ <boolean-expression>, <true-case>, <false-case> ] }.

But you used it, like: { $cond: [ <boolean-expression>, <false-case>, <true-case> ] }.

If votes not exists or empty array (boolean condition is true) you should use [ { value : 0} ] instead of it (paste [ { value : 0} ] in 2 item of $cond operator array).
Also, length property is not accessable in this case.

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

2 Comments

Silly me. Thanks a lot. This did the trick: votes : { $cond : [ { $eq : ["$votes", [] ]}, [ { value : 0} ], '$votes'] }
What if I need to check if the array is either null or empty?
0

If you need to check for all: empty array, null and empty values you can do like this:

{
  $cond: [
    {
      $in: [
        "$my_array",
        [
          null,
          undefined,
          []
        ]
      ]
    },
    "inCaseTrueValue",
    "inCaseFalseValue"
  ]
}

Comments

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.