MongoDB mongoose Агрегированный запрос для возврата вложенных документов в отдельном объекте - PullRequest
0 голосов
/ 29 августа 2018

Учитывая следующую схему:

const usersSchema = Schema({
  image    : {type: String},
  firstName: {type: String},
  lastName : {type: String},
  club    : {type: String, ref: 'clubs'}
}, {strict: true, useNestedStrict: true});
const Users = mongoose.model('Users', usersSchema);

const clubsSchema = Schema({
  image: {type: String},
  name : {type: String},
}, {strict: true, useNestedStrict: true});
const clubs = mongoose.model('clubs', clubsSchema);

Итак, у вас есть список пользователей, и каждый пользователь принадлежит к клубу, который сохраняется как ссылка на поддокумент.

Теперь у меня есть сводный запрос для поиска. (примечание: мой фактический запрос и схема намного сложнее, со многими поддокументами, я упростил их для этого поста)

let activePage = 0;
let resultsPerPage = 10;
let results = await Users.aggregate([
    {$sort: {firstName: 1, lastName: 1, club.name: 1}},
    {$lookup: {from: 'clubs', localField: 'club', foreignField: '_id', as: 'club'}},
    {$unwind: "$club"},
    {$project: {"_id": true, "image": true, "firstName": true, "lastName": true, "club._id": true, "club.name": true, "club.image": true}},
    {$match: {firstName: "Dave"}},
    {$group: {
      _id      : '$_id',
      image    : {$first: "$image"},
      firstName: {$first: "$firstName"},
      lastName : {$first: "$lastName"},
      club    : {
          $first: {
            _id  : "$club._id",
            name : "$club.name",
            image: "$club.image"
          }
        }
      }
    }},
    {$facet: {count:  [{$count: "count"}], records: [{$skip: activePage}, {$limit: activePage * resultsPerPage}]}}
]);

Когда я запускаю запрос, я получаю следующие (примерные) данные:

results.count[0].count // 4
results.records: 

_id   | image  | firstName | lastName | club._id | club.name | club.image
111   | <data> | Dave      | Burns    | c123     | admins    | <data>
222   | <data> | Dave      | Simpson  | c123     | admins    | <data>
333   | <data> | Dave      | Sanchez  | c123     | admins    | <data>
444   | <data> | Dave      | Smith    | c456     | losers    | <data>

До этого момента все работало точно так, как задумано.

Но мне не нравится тот факт, что данные клуба повторяются для каждой записи ... идентификатор клуба, имя и изображение дублируются 3 раза. Boo!

Что я хочу сделать, так это иметь его, чтобы я сохранил club._id в данных записи, а затем получил другое свойство в объекте результатов, который содержал бы соответствующие клубы.

Я хочу закончить с этим:

results.count[0].count // 4
results.records: 
_id   | image  | firstName | lastName | club._id
111   | <data> | Dave      | Burns    | c123    
222   | <data> | Dave      | Simpson  | c123    
333   | <data> | Dave      | Sanchez  | c123    
444   | <data> | Dave      | Smith    | c456    
results.clubs:
_id   | image  | name   
c123  | <data> | admins 
c456  | <data> | losers 

Таким образом, данные клуба не дублируются, и, таким образом, информация, передаваемая с сервера клиенту, значительно уменьшается. Затем на стороне клиента, когда я отображаю список, я могу сделать перекрестную ссылку, найти клуб для каждого пользователя и отобразить соответствующие данные.

Вопрос:

Есть ли способ в агрегированном запросе сделать это?

Я уже знаю, что могу сделать заполнение после факта или другого "после факта" поиска и запросов и тому подобного - но я не хочу этого делать. Я бы предпочел, чтобы все было сделано за один раз, потому что я обнаружил, что когда все сказано и сделано, это гораздо быстрее. Кроме того, в запрос встроена нумерация страниц и тому подобное ... Я не хочу повторять результаты после выполнения запроса, чтобы заполнить отсутствующие данные, если я могу помочь.

Кто-нибудь знает, можно ли это сделать?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...