Я пытаюсь вернуть имя и фамилию пользователя, создавшего документ, а также того, кто последним его модифицировал. Я использую populate()
JOIN между двумя коллекциями, но у меня это не сработало.
это территориальная модель
var mongo = require('mongoose'),
validator = require('mongoose-unique-validator'),
Schema = mongo.Schema
var model = new Schema({
NAME: { type: String, required: true, unique: true, max: 50, min: 3 },
STATUS: { type: String, default: 'active' },
ADDED_BY: { type: Schema.Types.ObjectId, ref: 'users' },
ADDED_DATE: { type: Date, default: Date.now },
MODIFY_BACKLOG :[{
USER: { type: Schema.Types.ObjectId, ref:'users' },
DATE: { type: Date, default: Date.now },
CURRENT: { type: String },
MODIFIED: { type: String }
}]
}, {collection :'areas'})
model.plugin( validator, { message: 'The {PATH} is not valid or duplicated' } )
module.exports = mongo.model('Area', model )
Как видите, индексы ADDED_BY
относятся MODIFY_BACKLOG.USER
к коллекции users
.
Это модель пользователей
var mongo = require('mongoose'),
validator = require('mongoose-unique-validator'),
Schema = mongo.Schema
var userSchema = new Schema({
PERSONAL_DATA: {
NAME: { type: String, required: [ true, 'The name is necessary' ], max: 50 },
LAST_NAME: { type: String, required: [ true, 'the lastname is necessary' ], max: 100 },
PHOTO: { type: String, max: 100 },
BIRTHDAY: { type: Date },
MARITIAL_STATUS: { type: Schema.Types.ObjectId, ref: 'maritial_statuses' },
GENDER: { type: String, max: 1 },
EMAIL: { type: String, required: true },
},
COMPANY_DATA: {
JOB: { type: Schema.Types.ObjectId, ref: 'jobs' },
AREA: { type: Schema.Types.ObjectId, ref: 'areas' },
ROLE: { type: Schema.Types.ObjectId, ref: 'roles' },
BOSS: { type: Schema.Types.ObjectId, ref: 'users' },
}
}, { collection: 'users' } )
model.plugin( validator, { message: 'The {PATH} is not valid or duplicated' } )
module.exports = mongo.model('User', userSchema )
Поскольку информация в этой модели очень надежна, я решил разделить ее на PERSONAL_DATA, COMPANY_DATA
два других индекса PAYMENT_DATA, ENGINE_DATA
, каждый из которых содержит индексы, которые относятся к имени отца, но они меня не интересуют, потому что они не имеют ничего общего с вопрос и это модель ок. 300 строк.
Внутри COMPANY_DATA.AREA
находится область, к которой принадлежит пользователь, я не думаю, что это имеет отношение к этой проблеме, но на всякий случай.
Это путь , используемый моделью области
var express = require('express'),
Areas = require('../../models/catalogs/areas'),
app = express()
app.get('/:from', (req, res) => {
var from = parseInt( req.params.from )
var populate = {
path: 'users',
select: 'NAME LAST_NAME'
}
Areas.find()
.sort('NAME').populate( populate )
.limit(10).skip(from)
.exec((error, data) => {
if (error) {
return res.status(500).json({
success: false,
error
})
}
Areas.count({}, ( err, total ) => {
res.status(200).json({
success: true,
data,
total
})
})
})
})
module.exports = app
populate()
Я передаю одноименную переменную в метод , где я делаю ссылку на коллекцию и какие данные мне нужны от пользователя. Здесь я застрял, потому что он не приносит мне информацию о пользователе, он приносит мне только информацию о районе, и здесь у меня есть три вопроса.
Как я могу заставить JOIN коллекций уважать меня?
Как мне сказать, что нужные мне индексы находятся не явно на верхнем уровне документа, а внутри PERSONAL_DATA? я пытался с
var populate = {
path: 'users',
select: 'PERSONAL_DATA.NAME PERSONAL_DATA.LAST_NAME'
}
Но это все равно, наконец
Индекс MODIFY_BACKLOG
в модели области также имеет ObjectId пользователя, который внес изменения, как я могу сказать, что JOIN для пользователей также выполняется для этого индекса?
оставляю пример ответа
{
"success": true,
"data": [{
"STATUS": "active",
"_id": "5c547f4adadf433914f72c8c",
"NAME": "Contabilidad y Finanzas",
"ADDED_BY": "5c4f562deec6f4defeea759b",
"ADDED_DATE": "2019-02-01T17:18:02.680Z",
"__v": 0,
"MODIFY_BACKLOG": []
}, {
"STATUS": "active",
"_id": "5c645f476491cf093c51c38e",
"NAME": "Recursos Humanos",
"ADDED_BY": "5c4f562deec6f4defeea759b",
"ADDED_DATE": "2019-02-13T18:17:43.036Z",
"__v": 0,
"MODIFY_BACKLOG": [{
"DATE": "2019-02-13T19:43:18.273Z",
"_id": "5c6473561370462754939107",
"USER": "5c4f562deec6f4defeea759b",
"CURRENT": "active",
"MODIFIED": "{\"STATUS\":\"inactive\"}"
}, {
"DATE": "2019-02-13T19:43:24.213Z",
"_id": "5c64735c1370462754939108",
"USER": "5c4f562deec6f4defeea759b",
"CURRENT": "inactive",
"MODIFIED": "{\"STATUS\":\"active\"}"
}]
}],
"total": 5
}
У вас есть некоторые ошибки, которые я буду подробно описывать постепенно
ПРОБЛЕМА
Вы хотите запросить базу данных Mongo из приложения Express, используя Mongoose в качестве ODM.
Документ, к которому обращаются, принадлежит коллекции
areas
и имеет поле, которое ссылается наObjectId
другой документ. А именно, полеADDED_BY
содержит ссылку на поле_id
документа в коллекцииusers
.Выполняемый запрос использует метод
populate()
(Mongoose), чтобы сообщить движку Mongo, что вы хотите вернуть набор полей (из документа коллекцииusers
) в поле, содержащем ссылку.Используется именованный объект,
populate
который передается методу в качестве аргумента.populate()
РЕШЕНИЕ
Здесь я укажу на ошибки, которые вы делаете, а также некоторые предложения:
Первая ошибка, которую я вижу в вашем коде, связана с определением модели
User
:Эта строка должна быть:
Я думаю, это ошибка "копировать и вставить"
Тогда одно предложение, которое я могу дать вам, заключается в том, как вы определяете свою ссылку:
Обычно я использую имя в единственном числе, которое также соответствует модели, на которую я ссылаюсь, а не названию коллекции. Как я уже сказал, это всего лишь предложение:
Наконец, то, как вы используете метод
populate()
, является причиной вашей проблемы.В официальной документации Mongoose сказано следующее: (собственный перевод)
Учитывая это, проблема в том, что вы не правильно указываете путь, на который хотите заменить данные. Мне кажется, что вы ошибочно полагаете, что это
ref
имя следует использовать в пути, который вы хотите заменить.Итак, ваш объект
populate
должен выглядеть так:Вы можете увидеть, что я использую
PERSONAL_DATA.NAME
иPERSONAL_DATA.LAST_NAME
как параметры файлаselect
.Что касается той
array
, которая хранит журнал модификаций. Решение такое же, но с небольшой разницей. Давайте создадим объект с именемpopulateLog
следующим образом:Как видите, поле
path
объекта равноMODIFY_BACKLOG.USER
, и именно поле этогоUSER
объектаMODIFY_BACKLOG
мы хотим заполнить дополнительными данными.Mongoose заполнит каждый элемент
array
данными, которые мы у него запрашиваем.Теперь мы можем вызвать метод в нашей цепочке методов:
Как видите, я вызываю метод дважды
populate()
и каждому передаю соответствующий объект.Внеся эти небольшие изменения, ваш код должен работать.
Пример ответа, использующего
GET
Postman для моей собственной реализации, следующий:Как видите, возвращенный документ содержит информацию, которую мы заполнили с помощью метода
populate()
, как для поля , такADDED_BY
и для поляMODIFY_BACKLOG
, так как последнее представляет собойarray
, каждый элементarray
содержит правильную информацию.Я надеюсь, что это поможет вам решить проблему.