MongoDB запросить несколько моделей - PullRequest
1 голос
/ 27 апреля 2020

У меня есть User и Training модель. Оба свойства likes содержат массив. Идея заключается в том, что я хотел бы создать какую-то функциональность «добавить в избранное».

Модель пользователя

likes: [
    {
      type: mongoose.Schema.ObjectId,
      ref: 'Training',
    },
  ],

Модель обучения

likes: [
    {
      type: mongoose.Schema.ObjectId,
      ref: 'Training',
    },
  ],

В моем контроллере я создал функцию, которая отвечает для заполнения идентификатора пользователя в обучении и наоборот.

exports.favoriteTraining = catchAsync(async (req, res, next) => {
  const user = await User.findById(req.user.id);
  const training = await Training.findById(req.params.id);

  const trainingLikes = training.likes.filter((like) => {
    return like.toString() === req.user.id;
  });

  if (trainingLikes.length > 0) {
    return next(new AppError('Training already liked', 400));
  }

  user.likes.unshift(req.params.id);
  training.likes.unshift(req.user.id);

  await user.save({ validateBeforeSave: false });
  await training.save({ validateBeforeSave: false });

  res.status(201).json({
    status: 'success',
    data: {
      user,
      training,
    },
  });
});

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

1 Ответ

1 голос
/ 28 апреля 2020

Вы можете упростить свою пользовательскую схему и логику c, чтобы избрать тренинг, удалив лайки из пользовательской модели.

Вот шаги:

1-) Удалить лайки из пользовательской модели

const mongoose = require("mongoose");

const UserSchema = new mongoose.Schema({
  name: String,
});

module.exports = mongoose.model("User", UserSchema);

2-) Теперь нам нужно только изменить массив лайков в обучении модель.

exports.favoriteTraining = catchAsync(async (req, res, next) => {
  const loggedUserId = req.user.id;

  let training = await Training.findById(req.params.id);

  const alreadyLiked = training.likes.find((like) => like.toString() === loggedUserId) !== undefined;

  if (alreadyLiked) return next(new AppError("Training already liked", 400));

  training.likes.push(loggedUserId);

  training = await training.save({ validateBeforeSave: false });

  res.status(201).json({
    status: "success",
    data: {
      training,
    },
  });
});

Как вы видите, мы сделали здесь только 2 дБ (было 4). Также я советую использовать push вместо unshift, unshift изменяет индекс всех элементов в массиве, pu sh добавляет только новый элемент в конец.

3-) Так как мы удалили лайки от пользователя, нам нужно найти способ ссылки на тренинги от пользователя.

Допустим, мы хотим найти пользователя по идентификатору и получить тренинги, которые он / она предпочитает. Для этого мы можем использовать агрегацию mongodb $ lookup . (Мы могли бы также использовать функцию виртуального заполнения mon goose, но поиск лучше.)

exports.getUserAndFavoritedTrainings = catchAsync(async (req, res, next) => {
  const loggedUserId = req.user.id;

  const result = await User.aggregate([
    {
      $match: {
        _id: mongoose.Types.ObjectId(loggedUserId),
      },
    },
    {
      $lookup: {
        from: "trainings", //must be physcial name of the collection
        localField: "_id",
        foreignField: "likes",
        as: "favorites",
      },
    },
    {
      $project: {
        __v: 0,
        "favorites.likes": 0,
        "favorites.__v": 0,
      },
    },
  ]);

  if (result.length > 0) {
    return res.send(result[0]);
  } else {
    return next(new AppError("User not found", 400));
  }
});

TEST:

Допустим, у нас есть 2 пользователя:

{
    "_id" : ObjectId("5ea7fb904c166d2cc42fd862"),
    "name" : "Krzysztof"
},
{
    "_id" : ObjectId("5ea808988c6f2207c8289191"),
    "name" : "SuleymanSah"
}

И эти два тренинга:

{
    "_id" : ObjectId("5ea7fbc34c166d2cc42fd863"),
    "likes" : [
        ObjectId("5ea7fb904c166d2cc42fd862"), // Swimming favorited by Krzysztof
        ObjectId("5ea808988c6f2207c8289191") // Swimming favorited by SuleymanSah
    ],
    "name" : "Swimming Training",
},
{
    "_id" : ObjectId("5ea8090d6191c60a00fe9d87"),
    "likes" : [
        ObjectId("5ea7fb904c166d2cc42fd862") // Running favorited by Krzysztof
    ],
    "name" : "Running Training"
}

Если вошедший в систему пользователь - Кшиштоф, результат будет таким:

{
    "_id": "5ea7fb904c166d2cc42fd862",
    "name": "Krzysztof",
    "favorites": [
        {
            "_id": "5ea7fbc34c166d2cc42fd863",
            "name": "Swimming Training"
        },
        {
            "_id": "5ea8090d6191c60a00fe9d87",
            "name": "Running Training"
        }
    ]
}

Вы можете поиграть с этим агрегатом в этом детская площадка

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