Search code examples
mongodbmongoose

MongoDB: Adding projection rule in find returns all properties of document


Problem

I have a collection of "Tests", which contains properties like name, category and an array of questions.

I want to select (projection) only one item from the array. I am using the $slice operator inside the selection, like {questions:{$slice:[1,1]}}. However, it returns all other properties of the Test document. But, if I only use {questions:1}, it just returns the questions property from the document.

Playground link to my problem

I want to only return the questions field, with the "sliced" item, but not the other properties from the document, without using verbose "name:0, category:0", since schema might change dynamically. I just want to select the questions field.


A more detailed explanation:

If I run the following query

db.collection.find({
  "key": 1
},
{
  "questions": 1,
})

I get what I expect, an object with only the "questions" property in it, since that's what I am selecting / projecting with "questions":1.

However, with the following query

db.collection.find({
  "key": 1
},
{
  "questions": {
    "$slice": [1, 1] // <-- The only difference is here compared to previous
  },
})

It returns the "questions" but also other properties in the document like name, category, etc.


Solution

  • There are 2 syntaxes for the $slice operator:

    projection:

    { $slice: [ <number>, <number> ] }
    

    https://www.mongodb.com/docs/manual/reference/operator/projection/slice/

    and aggregation:

    { $slice: [ <array>, <position>, <n> ] }
    

    https://www.mongodb.com/docs/manual/reference/operator/aggregation/slice/

    The projection form of the operator behaves like $addFields, as you noticed, while the aggregation form will behave the way you expected.

    Try

    db.collection.find(
        {"key": 1},
        {"questions": {
            "$slice": ["$questions", 1, 1] 
        }}
    )
    

    Playground