Я работаю с Mongoose и пытаюсь развернуть/заполнить поле comment.attachments в конвейере агрегации. Вот соответствующая часть моего кода:
const result = await Ticket.aggregate([
{ $match: { $expr: { $eq: ['$_id', { $toObjectId: "667293eca3a67d7c5d9ff1e2" }] } } },
{ $unwind: '$comments' },
{ $match: { $expr: { $eq: ['$comments._id', { $toObjectId: "667382f627df37eb4e7a3220" }] } } },
])
Этот запрос успешно извлекает документ билета и разворачивает массив комментариев. Однако поле comment.attachments остается пустым массивом, даже если с комментарием связаны вложения.
[
{
_id: new ObjectId('667293eca3a67d7c5d9ff1e2'),
referenceNo: 'TCK_06-19-2024_0001',
subject: new ObjectId('6670dad080ea03a681f70295'),
description: 'pero ang totoo, di bali na ako. ikaw lang iniisip ko.',
priority: 'medium',
status: 'open',
initiator: new ObjectId('6670da9d80ea03a681f70292'),
createdBy: new ObjectId('667106fff8abeeb0d87341ba'),
assignedTo: null,
attachments: [ [Object], [Object] ],
comments: {
userId: new ObjectId('6670db4180ea03a681f7029e'),
content: '2nd comment w atta',
attachments: [Array],
_id: new ObjectId('667382f627df37eb4e7a3220'),
createdAt: 2024-06-20T01:16:38.190Z,
updatedAt: 2024-06-20T01:16:38.190Z
},
createdAt: 2024-06-19T08:16:44.129Z,
updatedAt: 2024-06-20T02:14:51.282Z,
__v: 0
}
]
Вот мои модели для справки:
Модель билета
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const ticketCommentSchema = require('./ticketCommentModel');
const ticketAttachmentSchema = require('./ticketAttachmentModel');
const ticketSchema = new Schema({
// ... other schema properties
comments: [ticketCommentSchema],
attachments: {
type: [ticketAttachmentSchema],
required: true,
validate: [attachmentsArray => attachmentsArray.length > 0, 'At least one attachment is required']
},
}, {
timestamps: true
});
module.exports = mongoose.model('Ticket', ticketSchema);
Модель комментариев к заявкам
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const ticketAttachmentSchema =
require('./ticketAttachmentModel');
const ticketCommentSchema = new Schema({
userId: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
required: true
},
content: {
type: String,
trim: true,
required: true
},
attachments: [ticketAttachmentSchema]
}, {
timestamps: true
});
module.exports = ticketCommentSchema;
Модель прикрепления билета
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const ticketAttachmentSchema = new Schema({
// ... attachment schema properties
}, {
timestamps: true
});
module.exports = ticketAttachmentSchema;
Мой вопрос:
Как я могу изменить конвейер агрегации, чтобы развернуть или заполнить поле comment.attachments и получить сведения о вложении в результатах запроса?
Я искал в Интернете решения, но не нашел ничего конкретного для этого сценария. Любая помощь будет принята с благодарностью!
Я пробую этот конвейер агрегации
const result = await Ticket.aggregate([
{ $match: { $expr: { $eq: ['$_id', { $toObjectId: "667293eca3a67d7c5d9ff1e2" }] } } },
{ $unwind: '$comments' },
{ $match: { $expr: { $eq: ['$comments._id', { $toObjectId: "667382f627df37eb4e7a3220" }] } } },
{
$unwind: {
path: "$comments.attachments",
preserveNullAndEmptyArrays: true
}
},
])`
и он возвращает эти данные
[
{
_id: new ObjectId('667293eca3a67d7c5d9ff1e2'),
referenceNo: 'TCK_06-19-2024_0001',
subject: new ObjectId('6670dad080ea03a681f70295'),
description: 'pero ang totoo, di bali na ako. ikaw lang iniisip ko.',
priority: 'medium',
status: 'open',
initiator: new ObjectId('6670da9d80ea03a681f70292'),
createdBy: new ObjectId('667106fff8abeeb0d87341ba'),
assignedTo: null,
attachments: [ [Object], [Object] ],
comments: {
userId: new ObjectId('6670db4180ea03a681f7029e'),
content: '2nd comment w atta',
attachments: [Object],
_id: new ObjectId('667382f627df37eb4e7a3220'),
createdAt: 2024-06-20T01:16:38.190Z,
updatedAt: 2024-06-20T01:16:38.190Z
},
createdAt: 2024-06-19T08:16:44.129Z,
updatedAt: 2024-06-20T02:14:51.282Z,
__v: 0
},
{
_id: new ObjectId('667293eca3a67d7c5d9ff1e2'),
referenceNo: 'TCK_06-19-2024_0001',
subject: new ObjectId('6670dad080ea03a681f70295'),
description: 'pero ang totoo, di bali na ako. ikaw lang iniisip ko.',
priority: 'medium',
status: 'open',
initiator: new ObjectId('6670da9d80ea03a681f70292'),
createdBy: new ObjectId('667106fff8abeeb0d87341ba'),
assignedTo: null,
attachments: [ [Object], [Object] ],
comments: {
userId: new ObjectId('6670db4180ea03a681f7029e'),
content: '2nd comment w atta',
attachments: [Object],
_id: new ObjectId('667382f627df37eb4e7a3220'),
createdAt: 2024-06-20T01:16:38.190Z,
updatedAt: 2024-06-20T01:16:38.190Z
},
createdAt: 2024-06-19T08:16:44.129Z,
updatedAt: 2024-06-20T02:14:51.282Z,
__v: 0
}
]
он превращает comment.attachments в объект, но все равно не заполняет данные вложений, Также к комментарию есть 3 вложения.
🤔 А знаете ли вы, что...
MongoDB предоставляет средства для создания резервных копий и восстановления данных...
Эта агрегация должна дать вам желаемый результат.
$match
: тот ticket
, который вы хотите. Обратите внимание на использование конструктора new mongoose.Types.ObjectId()
, чтобы вам не приходилось использовать $expr
и конвертировать $toObjectId
.$set
: массив comments
для вывода только $filter
, совпадающего comments
, у которого _id
равен ObjectId("6678d63114c2fef2955395f0")
.$unwind
: массив comments
для следующего этапа. Объект должен быть только один, так как вы совпали по _id
.$set
: массив comments.attachments
для вывода только $filter
, совпадающего attachments
, у которого _id
равен ObjectId("6678d63114c2fef2955395f1")
.const result = await Ticket.aggregate([
{
$match: {
_id: new mongoose.Types.ObjectId("6678d3b714c2fef2955395ca"),
"comments._id": new mongoose.Types.ObjectId("6678d63114c2fef2955395f0")
}
},
{
$set: {
comments: {
$filter: {
input: "$comments",
as: "c",
cond: {
$eq: [
"$$c._id",
new mongoose.Types.ObjectId("6678d63114c2fef2955395f0")
]
}
}
}
}
},
{
$unwind: "$comments"
},
{
$set: {
"comments.attachments": {
$filter: {
input: "$comments.attachments",
as: "ca",
cond: {
$eq: [
"$$ca._id",
new mongoose.Types.ObjectId("6678d63114c2fef2955395f1")
]
}
}
}
}
}
]);
Рабочий пример смотрите ЗДЕСЬ.