Mongoose - Как собирать содержимое из двух коллекций - PullRequest
1 голос
/ 28 июня 2019

Как я могу использовать для этого агрегатную операцию Mongoose?По сути, у меня есть две коллекции - «Пост» и «Профиль».Пользовательский oid с именем «user» является общей ссылкой между ними.Я хочу использовать идентификатор из «Post», чтобы найти элемент «handle» из «Profile» и объединить эти результаты, чтобы дескриптор пользователя был включен в ответ.

Вот как я смогчтобы достичь этого при поиске одного сообщения:

// @route   GET api/posts/:id
// @desc    Get post by id
// @access  Public
router.get("/:id", (req, res) => {
  Post.findById(req.params.id)
    .then(post => {
      Profile.findOne({ user: post.user })
        .then(profile => res.json({ ...post._doc, userHandle: profile.handle }));
    })
    .catch(err => res.status(404).json({ "not found": err }));
});

Однако, когда я попытался распространить этот подход (используя операцию карты) на GET, который возвращает ВСЕ сообщения, он стал неработоспособным.

// @route   GET api/posts
// @desc    Get all the posts
// @access  Public
router.get("/", (req, res) => {
  Post.find()
    .sort({ date: -1 })
    .then(posts =>
      posts.map(
        post =>
          Profile.findOne({ user: post.user })
            .then(profile => (
              {
                ...JSON.parse(JSON.stringify(post)),
                userHandle: profile.handle
              }))
      ))
    .then(posts => res.json(posts))
    .catch(err => res.status(404).json({ "none found": err }));
});

Другими словами, если у меня POST:

{
    "_id": {
        "$oid": "5d1523b98d9dd16d832a8c5e"
    },
    "user": {
        "$oid": "5d1504e29dc0bd55461adca7"
    },
    "recipeName": "Pizza",
    "ingredients": "Flour and sauch"
}

и PROFILE:

{
    "_id": {
        "$oid": "5d1505089dc0bd55461adca8"
    },
    "user": {
        "$oid": "5d1504e29dc0bd55461adca7"
    },
    "handle": "jack",
    "status": "Developer"
}

тогдачто мне действительно нужно, так это объект JSON (когда я запрашиваю сообщение): (обратите внимание, что теперь присутствует userHandle)

{
    "_id": {
        "$oid": "5d1523b98d9dd16d832a8c5e"
    },
    "user": {
        "$oid": "5d1504e29dc0bd55461adca7"
    },
    "recipeName": "Pizza",
    "ingredients": "Flour and sauch",
    "userHandle": "jack"
}

Мой GET должен вернуть целый массив этих сообщений.

Ответы [ 2 ]

0 голосов
/ 28 июня 2019
getUserDetails: (request, response, next) => {
        try {
            let aggrQuery = [
                {
                    $lookup: {
                        from: "Profiles",
                        localField: "Id",//key name of common id in post collection as a reference
                        foreignField: "profileId",// key name of common id in profile collection
                        as: "userDetails"// handle element as well as other data in profile collection will be stored in userDetails
                    }
                },
                {
                    "$project": {
                       //we have to carry "_id", "ingredients","recipeName","user" of post collection for the next projection,and whole user information is stored in "userDetails"
                        "_id": 1,
                        "ingredients":1,
                        "recipeName":1,
                        "user":1,
                        userDetails : { $arrayElemAt : 
                      ["$userDetails", 0]}
                    }
                },
                {
                    "$project": {
                        //finally we prepare required data set for response,"_id", "ingredients","recipeName","user" of post collection,and only userHandle of Profiles from userDetails array(which contains all profile data)
                        "_id": "$_id",
                        "ingredients":"$ingredients",
                        "recipeName":"$recipeName",
                        "user":"$user",
                        "userDetails":{
                           "userHandle" :"$userDetails.userHandle",
                           "additionField1":"$userDetails.additionField1",
                           "additionField2":"$userDetails.additionField2",
                         }     
                    }
                }
            ]
            Post.aggregate(aggrQuery).exec((err, result) => {
                if(err){
                  response.json({
                      isError: true,
                      statuscode: 404,
                      details: null
                  })
                }
                else{
                   response.json({
                    isError: false,
                    statuscode: 200,
                    details: result
                  })
                }
            })
        }
        catch{
            response.json({
                isError: true,
                statuscode: 404,
                details: null
            });
        }
    },
0 голосов
/ 28 июня 2019
Post.find().sort({date: -1}).then((posts) => {
  Post.populate(posts, [{
    path: 'user',
    select: {}, // projection
    model: User // User model
  }], (err, posts) => {
    if (err) return next(err);
    return res.json(posts);
  });
});

Подробнее о мангусте заполнить

Редактировать

Если вы не хотите каждый раз включать model, вы можете добавить ref(имя коллекции) в поле Schema, и она автоматически определит модель!

Пример:

const postSchema = Schema({
  ...
  user: { type: Schema.Types.ObjectId, ref: 'Users' }
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...