Как подсчитать количество вхождений ObjectId в массиве ObjectIds и прикрепить результат к каждому возвращаемому документу?

1

У меня есть схема Tag:

const TagSchema = new Schema({
  label: {type: String, unique: true, minlength: 2},
  updatedAt: {type: Date, default: null},
  createdAt: {type: Date, default: new Date(), required: true},
  createdBy: {type: mongoose.Schema.Types.ObjectId, ref: 'Account', default: null}
});

const Tag = mongoose.model('Tag', TagSchema);

Тогда у меня есть схема Page:

const PageSchema = new Schema({
  tags: {type: [{type: mongoose.Schema.Types.ObjectId, ref: 'Tag'}], default: [], maxlength: 5}
});

const Page = mongoose.model('Page', PageSchema);

Как вы можете видеть, что содержит Tag ссылки в его tags массива.

Теперь мне нужно сделать, когда я получаю все теги через /tags, мне также нужно подсчитать количество раз, когда каждый тег используется на всех Page.

Поэтому, если Tag используется 2 раза на всех Page, он должен установить свойство .occurrences на возвращаемом теге. Например, это будет ответ от /tags:

[
 {_id: '192398dsf7asdsdds8f7d', label: 'tag 1', updatedAt: '20170102', createdAt: '20170101', createdBy: '01238198dsad8s7d78ad7', occurrences: 2},
 {_id: '19239asdasd8dsf7ds8f7d', label: 'tag 2', updatedAt: '20170102', createdAt: '20170101', createdBy: '01238198dsad8s7d78ad7', occurrences: 1},
 {_id: '192398dsf7zxccxads8f7d', label: 'tag 1', updatedAt: '20170102', createdAt: '20170101', createdBy: '01238198dsad8s7d78ad7', occurrences: 5},
]

Я бы предположил, что я мог бы добиться этого довольно легко в мангусте pre('find'):

TagSchema.pre('find', function() {

  Page.count({tags: this._id}, (err, total) => {
    this.occurrences = total;
  });
});

Однако здесь есть две проблемы:

  • Page.count выдает ошибку, говоря, что это не функция, которую я не понимаю, потому что я использую ее где-то еще отлично. И Page импортирована должным образом. Предполагая, что вы не можете использовать count в крючке или что-то подобное.

  • this не документ Tag.

Поэтому я предполагаю, что то, как я это делаю, совершенно неверно.

Поскольку я новичок в MongoDB, возможно, кто-то может предоставить мне лучшее, работающее решение моей проблемы?

  • 0
    здесь Page.count({tags: this._id}, (err, total) => { this.occurrences = total; }); что ты хочешь делать ?
  • 0
    @hardy Тяжело, я не понимаю твой вопрос.
Показать ещё 4 комментария
Теги:
mongoose

2 ответа

1
Лучший ответ
db.Page.aggregate([ 
{
  $unwind:"$tags"
},
{
  $group:{ 
    _id:"$tags", 
    occurrences:{$sum:1}
  }
},
{
  $lookup:{ //get data for each tag
    from:"tags",
    localField:"_id",
    foreignField:"_id",
    as:"tagsData"
  }
},
{
$project:{
  tagData:{$arrayElemAt: [ "$tagsData", 0 ]},
  occurrences:1
}
}
{
  $addFields:{ 
    "tagData._id":"$_id",
    "tagData.occurrences":"$occurrences"
  }
},
{
   $replaceRoot: { newRoot: "$tagData" }
}
])
  • 0
    Не могли бы вы добавить объяснение?
  • 0
    Я добавил комментарии. пожалуйста, проверьте
Показать ещё 6 комментариев
0

Хорошо сначала, вам нужно getQuery(), это позволяет вам получить доступ к свойствам, с которыми вы находите tag. поэтому, если вы найдете тег _id, у вас будет доступ к нему в pre hook this.getQuery()._id

Во-вторых, вам понадобится использовать "параллельное" промежуточное программное обеспечение, которое можно найти в документах. Это позволяет поисковому методу подождать до тех пор, пока не будет вызвана done функция, поэтому он ждет, пока тег не будет обновлен новым номером вхождения.

Поскольку объект не может получить доступ к Inn на pre крючок, как это до сих пор не найден, вы будете иметь, чтобы использовать findOneAndUpdate метод в pre крючке.

Поэтому код должен выглядеть так:

Метод find:

Tag.find({ _id: "foo"}, function (err, foundTag) {
  console.log(foundTag)
})

pre крюк:

TagSchema.pre('find', true, function (next, done) {
  mongoose.models['Page'].count({ tags: this.getQuery()._id }, (err, total) => {
    mongoose.models['Tag'].findOneAndUpdate({ _id: this.getQuery()._id }, { occurrences: total }, function () {
      next()
      done()
    })
  });
});

Ещё вопросы

Сообщество Overcoder
Наверх
Меню