batchSize field name ignored in Field Projection

I have a user_batch collection. It contains following documents:

[{
  _id: ObjectId("594baf96256597ec035df23c"),
  name: "Batch 1",
  batchSize: 30,
  users:[]
 },
 {
  _id: ObjectId("594baf96256597ec035df234"),
  name: "Batch 2",
  batchSize: 50,
  users:[]
 }]

In find query I want to project only name and batchSize. But when I execute find query from nodejs, I'm getting entire document in query result. Query:

db.collection('user_batch').find({}, {name: 1, batchSize: 1}).toArray((err, result) => {
  if(err) 
    console.log(err)
  else
    console.log(result)
})

If I just pass {name: 1} then it will project _id and name. But if I pass batchSize then it will return entire document.

Note: I'm not facing this issue while executing this query in Mongo Shell

Answers:

Answer

You are correct that the driver incorrectly interprets this as the batchSize option and ignores the projection statement.

The correct way to do this though in modern driver releases is to actually use the .project() "cursor method" instead. This is more consistent with other language driver implementations.

    db.collection('collection').find()
      .project({ name: 1, batchSize: 1})
      .toArray();

As a full demonstration:

const mongodb = require('mongodb'),
      MongoClient = mongodb.MongoClient;


(async function() {

  let db;

  try {
    db = await MongoClient.connect('mongodb://localhost/test');

    // New form uses .project() as a cursor method
    let result = await db.collection('collection').find()
      .project({ name: 1, batchSize: 1})
      .toArray();

    console.log(JSON.stringify(result,undefined,2));

    // Legacy form confuses this as being a legacy "cursor option"
    let other = await db.collection('collection')
      .find({},{ name: 1, batchSize: 1 })
      .toArray();

    console.log(JSON.stringify(other,undefined,2));

  } catch(e) {
    console.error(e)
  } finally {
    db.close()
  }

})()

Produces the output:

[
  {
    "_id": "594baf96256597ec035df23c",
    "name": "Batch 1",
    "batchSize": 30
  },
  {
    "_id": "594baf96256597ec035df234",
    "name": "Batch 2",
    "batchSize": 50
  }
]
[
  {
    "_id": "594baf96256597ec035df23c",
    "name": "Batch 1",
    "batchSize": 30,
    "users": []
  },
  {
    "_id": "594baf96256597ec035df234",
    "name": "Batch 2",
    "batchSize": 50,
    "users": []
  }
]

Where the first output form is the corrected one, using .project()

Answer

The syntax of Find has changed. Below is what I needed to know to solve this problem. This is excerpted from https://github.com/mongodb/node-mongodb-native/blob/master/CHANGES_3.0.0.md#find

Find

find and findOne no longer support the fields parameter. You can achieve the same results as the fields parameter by using Cursor.prototype.project or by passing the projection property in on the options object . Additionally, find does not support individual options like skip and limit as positional parameters. You must either pass in these parameters in the options object, or add them via Cursor methods like Cursor.prototype.skip.

2.x syntax:

const cursor = coll.find({ a: 42 }, { someField: 1 });

3.x syntax:

const cursor = coll.find({ a: 42 }).project({ someField: 1 });

/* OR */

const cursor = coll.find({ a: 42 }, { projection: { someField: 1 } });

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.