Как подсчитать числовые значения и получить одно значение для всех документов в Mongo / Node - PullRequest
0 голосов
/ 01 мая 2018

Я пытаюсь сделать то, что должно быть довольно простой операцией в моей среде mongoDB / Node. У каждого документа в коллекции, на которую я нацеливаюсь, есть поле "openBalance", которое является числовым значением. Все, что я хочу сделать, это найти totalOpenBalance, сложив все вместе.

Пока что при просмотре документации MongoDB $ add и $ sum, похоже, используются для выполнения операций над отдельными документами в коллекции, а не над самой коллекцией.

Это заставляет меня задуматься, есть ли другой подход к этому? Я пробовал множество конструкций, но ни одна из них не работает. Вот моя функция полностью:

exports.getClientData = async function (req, res, next) {
    let MongoClient = await require('../config/database')();
    let db = MongoClient.connection.db;

  let search, skip, pagesize, page, ioOnly = false, client;
  let docs = [];
    let records = 0;

  if (_.isUndefined(req.params)) {
      skip = parseInt(req.skip) || 0;
      search = JSON.parse(req.search);
      pagesize = parseInt(req.pagesize) || 0;
      page = parseInt(req.page) || 0;
      client = req.client || '';
      ioOnly = true;
  }
  else {
      skip = parseInt(req.query.skip) || 0;
      search = req.body;
      pagesize = parseInt(req.query.pagesize) || 0;
      page = parseInt(req.query.page) || 0;
      client = req.query.client || '';
  }

  search = {};

  if (skip === 0) {
      skip = page * pagesize;
  }

  if (client) {
    let arrClient = [];
    arrClient = client.split(",");
    if (arrClient) {
      // convert each ID to a mongo ID
      let mongoArrClient = arrClient.map(client => new mongo.ObjectID(client));
      if (mongoArrClient) {
        search['client._id'] = { $in: mongoArrClient };
      }
    }
  }

  console.log(search);

  let counter = 0;
  let count = await db.collection('view_client_data').find(search).count();

  let totalClients = await db.collection('view_client_data').find(search).count({ $sum: "client._id" });
  console.log('totalClients', totalClients);

  let totalOpenBalance = await db.collection('view_client_data').find(search).count({ $sum: { "$add" : "openBalance" } });
  console.log('totalOpenBalance', totalOpenBalance);

    db.collection('view_client_data').find(search).skip(skip).limit(pagesize).forEach(function (doc) {
        counter ++; {
      console.log(doc);
      docs.push(doc);
    }

    }, function (err) {
        if (err) {
            if (!ioOnly) {
                return next(err);
            } else {
                return res(err);
            }
    }
        if (ioOnly) {
            res({ sessionId: sessID, count: count, data: docs, totalClients: totalClients, totalOpenBalance: totalOpenBalance });
        }
        else {
      res.send({ count: count, data: docs, totalClients: totalClients, totalOpenBalance: totalOpenBalance });
        }
    });
}

Как вы можете видеть в приведенном выше коде, я получаю общее количество клиентов с этим кодом:

  let totalClients = await db.collection('view_client_data').find(search).count({ $sum: "client._id" });
  console.log('totalClients', totalClients);

Это прекрасно работает, складывая экземпляры клиента и давая мне общее количество.

Опять же, чтобы быть кристально чистым, я сталкиваюсь с проблемой в суммировании числового значения для всех значений openBalance. У каждого документа есть поле openBalance. Все, что я хочу сделать, это сложить их и вывести их в переменную под названием totalOpenBalance и передать это в ответе, который я отправляю, как я делаю для totalClients. Я пробовал множество вариантов, в том числе:

  let totalOpenBalance = await db.collection('view_client_data').find(search).count({ $sum: { "$add" : "openBalance" } });
  console.log('totalOpenBalance', totalOpenBalance);

и это:

  let totalOpenBalance = await db.collection('view_client_data').find(search).aggregate({ $sum: { "$add" : "openBalance" } });
  console.log('totalOpenBalance', totalOpenBalance);

... но, как я уже сказал, никто не работает. Иногда я получаю ошибку циклической ссылки, иногда aggregate is not a function error, а иногда и другие ошибки. Я ломал голову, пытаясь понять это - и я полагаю, что это не должно быть так сложно, как только я пойму необходимый синтаксис. Как я могу получить мои totalOpenBalance здесь?

Кстати, целевые документы выглядят примерно так:

    {
        "_id": "3hu40890sf131d361f1ad908",
        "client": {
            "_id": "4ft9d366121j04563be0b01d6",
            "name": {
                "first": "John",
                "last": "Smith"
            }
        },
        "openBalance": 128,
        "lastPurchaseDate": "2018-01-19T00:00:00.000Z"
    },

Ответы [ 2 ]

0 голосов
/ 01 мая 2018

$sum является оператором накопителя, который должен находиться в пределах $group или $project агрегатной конвейерной ступени . Чтобы также включить ваш фильтр search, вы можете включить в свой конвейер этап $match.

let result = await db.collection('view_client_data').aggregate([
    {$match: search},
    {$group: {_id: null, totalOpenBalance: {$sum: '$openBalance'}}}
]).next();
console.log(result.totalOpenBalance);
0 голосов
/ 01 мая 2018

Я думаю $group это то, что вы ищете.

Так, например, чтобы вычислить все поля openBalance

db.view_client_data.aggregate(
   [
      {
        $group: {
           _id : null
           totalOpenBalance: { $sum: "$openBalance" },
        }
      }
   ]
)

это должно вернуть вам объект, как {totalOpenBalance: 900}

Вот документация mongodb для некоторых других примеров. https://docs.mongodb.com/manual/reference/operator/aggregation/group/#pipe._S_group

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...