mongoose addfiled, aggregate или function

Mongoose Models:

const replySchema = new mongoose.Schema({
  text: {type:String, required: true, minlength: 1},
  delete_password: {type:String, required: true, minlength: 1, select: false},  
  reported: {type:Boolean, default: false},
  created_on: {type: Date, default: Date}
});
const replyModel = mongoose.model('MessageBoardReply', replySchema);

const threadSchema = new mongoose.Schema({
  text: {type:String, required: true, minlength: 1},
  replies: {type:[replySchema], default:[]},
  delete_password: {type:String, required: true, minlength: 1, select: false},
  reported: {type:Boolean, default: false},
  created_on: {type: Date, default: Date},
  bumped_on: {type: Date, default: Date},
  // replycount: ? replies.length auto
});
const threadModel = mongoose.model('MessageBoardThread', threadSchema);

const boardSchema = new mongoose.Schema({
  board: {type:String, required: true, minlength: 1},
  threads: {type:[threadSchema], default:[]}
});
const msgBoard = mongoose.model('MessageBoard', boardSchema);

Запрос:

msgBoard.findOne(
  {board:board},
  (err,data)=>{
    if(err || !data)
      return res.json(err);
    return res.json(data.threads)
  }
);

Ответ:

[
 {
  "_id":"626445037832c9629eba1f23",
  "text":"Text Thread",
  "created_on":"2022-04-23T18:27:14.927Z",
  "bumped_on":"2022-04-23T18:27:14.927Z",
  "replies":[],
  "replycount":0 // ? replies.length
 }
]

Вопросы:

  1. Можно ли, в схему добавить автоматический счётчик, без ручных махинаций при обновлениях.
  2. Можно ли, в схему добавить функцию, при запросе которая будет это делать.
  3. Через aggregate, как добавить каждому объекту из threads, поле "replycount": replies.length (то есть "board.threads[i].replycount" : board.threads[i].replies.length)

Ответы (1 шт):

Автор решения: Владимир Комяк

Один из вариантов обработки ответа:

let threads = (await msgBoard.aggregate([
  {$match: {board:board}},
  {$unset: ['threads.delete_password']},
  {$addFields: {'threads.replycount': -1}}
]))[0].threads;

threads = threads.map(th=>{
  th.replycount = th.replies.length;
  return th;
});

Очень похожее решение, но с ошибкой:

let threads = (await msgBoard.aggregate([
  {$match: {board:board}},
  {$unset: ['threads.delete_password']},
  {$addFields: {'threads.replycount':{
    $map:{
      input:'$threads',
      as:'th',
      in:{ $size:'$$th.replies'}
    }
  }}}
]))[0].threads;
// ответ будет весь массив, а не нужный элемент
→ Ссылка