У меня есть схема 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, возможно, кто-то может предоставить мне лучшее, работающее решение моей проблемы?
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" }
}
])
Хорошо сначала, вам нужно 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()
})
});
});
Page.count({tags: this._id}, (err, total) => {
this.occurrences = total;
});
что ты хочешь делать ?