javapedia.net
javapedia.net

Reputation: 2731

nodejs+mongodb access node.js object with document's _id field value in query

I am learning Mongodb to use with NodeJS. The below is my code:

let configMap = {
    '1': 10,
    '2': 12,
    '3': 13
}
let myData = await mongo_groups_collection.find({
    _id: {
        $in: [1,2,3]
    },
    active: true
}).project({
    '_id': 1,
    'name': 1,
    'members': 1,
    'messages': {
        $slice: [-(configMap[_id]), (DEFAULT_PAGE_SIZE_FILL * PAGE_SIZE) + (PAGE_SIZE - ((configMap[_id]) % PAGE_SIZE))] //Need to use _id to get configMap value

    }
}).toArray();

I am using "configMap" nodeJS variable in Mongo slice function to retrieve certain number of elements from the array. To retrieve I need to lookup using "_id" field value which I am not getting and encounter _id "undefined" error.

Upvotes: 2

Views: 277

Answers (1)

whoami - fakeFaceTrueSoul
whoami - fakeFaceTrueSoul

Reputation: 17915

That's because (configMap[_id]) gets compiled in node.js code but not on database as a query. So in code when this query gets compiled it's not able to find _id since you've not declared it as the way you did it for configMap variable.

You're expecting _id value to be actual _id from document. So, in case if you use (configMap[$_id]) it doesn't work that way cause you can't club a javascript object with documents field.

You can still do this using aggregate query like below - where we actually add needed v value as a field to document for further usage :

 /** Make `configMap` an array of objects */
var configMap = [
  { k: 1, v: 10 },
  { k: 2, v: 12 },
  { k: 3, v: 13 },
];

let myData = await mongo_groups_collection.aggregate([
  {
    $match: { _id: { $in: [1, 2, 3] }, active: true }
  },
  /** For each matched doc we'll iterate on input `configMap` array &
   *  find respective `v` value from matched object where `k == _id`  */
  {
    $addFields: {
      valueToBeSliced: {
        $let: {
          vars: { matchedK: { $arrayElemAt: [ { $filter: { input: configMap, cond: { $eq: ["$$this.k", "$_id"] } } }, 0 ] } },
          in: "$$matchedK.v",
        }
      }
    }
  },
  {
    $project: {
      messages: { $slice: ["$messages", { $subtract: [0, "$valueToBeSliced"] }, someInputValue ] },
      name: 1, members: 1
    }
  }
]).toArray();

Ref : $let

Note :

  1. In projection you don't need to mention this '_id': 1 as it's included by default.
  2. Since your query is using .find() you might be using $slice-projection-operator which can't be used in aggregation, instead we need to use $slice-aggregation-operator, both does same thing but have syntax variation, you need to refer to docs for that.
  3. Also in someInputValue you need to pass in value of (DEFAULT_PAGE_SIZE_FILL * PAGE_SIZE) + (PAGE_SIZE - ((configMap[_id]) % PAGE_SIZE)) - So try to use aggregation operators $divide to get the value. We're doing { $subtract: [0, "$valueToBeSliced"] } to convert positive valueToBeSliced to negative as we can't just do like -valueToBeSliced which we usually do in javaScript.

Upvotes: 1

Related Questions