简体   繁体   English

如何使用猫鼬拥有嵌套文档的计数字段

[英]How to have a count field of nested documents with Mongoose

I have a NodeJS API with Mongoose and I have troubles to make a count of documents nested in one document.我有一个带有 Mongoose 的 NodeJS API,我无法计算嵌套在一个文档中的文档数。 I have a schema called Profile and nested I have Experienced with an array of records.我有一个名为 Profile 的架构,并且嵌套了 I have Experienced 的记录数组。 My goal is to have an output as an example:我的目标是以输出为例:

{
    "username": "Jakos",
    "total_expereinces" = 2, << I want to add this
    "experience": [
        {
            "image": "",
            "_id": "5e26ff6d5be84a3aeeb2f7bc",
            "title": "Senior Dev",
            "role": "Dev",
            "company": "ArosaDev",
            "startDate": "2018-12-03T23:00:00.000Z",
            "endDate": null,
            "description": "",
            "area": "",
            "createdAt": "2020-01-21T13:41:01.873Z",
            "updatedAt": "2020-01-21T13:41:01.873Z"
        },
        {
            "image": "https://via.placeholder.com/150",
            "_id": "5e28791604718d7edb521c5b",
            "role": "Dev",
            "company": "Mammamia",
            "startDate": "2019-12-11T23:00:00.000Z",
            "endDate": null,
            "description": "",
            "area": "Copenhagen",
            "createdAt": "2020-01-22T16:32:22.848Z",
            "updatedAt": "2020-01-22T16:32:22.848Z"
        }
    ]
    }

At the moment I can get all without the count and my method looks like :目前我可以在没有计数的情况下获得所有内容,我的方法如下:

experienceRouter.get("/:username", async (req, res) => {
    console.log(req.params.username);
    try {
        const experiences = await Profiles.findOne(
            { username: req.params.username },
            { experience: 1, username: 1, _id: 0 }
        ).lean();

        if (experiences) res.send(experiences);

        res.status(404).send({ Message: "Not found any experience" });
    } catch (error) {
        res.status(500).send(err);
    }
});

I saw an example with aggregation and I tried to follow but the output is not as I have in my requirements as it is showing the whole profile in the output.我看到了一个带有聚合的示例,我试图遵循,但输出与我的要求不同,因为它在输出中显示了整个配置文件。

The method I tried with aggregation was:我尝试使用聚合的方法是:

experienceRouter.get("/:username", async (req, res) => {
    console.log(req.params.username);

    try {
        const numberOfExperiences = await Profiles.aggregate([
            { $match: { username: req.params.username } },
            { $unwind: "$experience" },
            { $project: { count: { $add: 1 } } },
            { $group: { _id: null, number: { $sum: "$count" } } }
        ]);
        const experiences = await Profiles.findOne({
            username: req.params.username
        });

        if (numberOfExperiences) {
            if (experiences) res.send({ numberOfExperiences, experiences });
        }
    } catch (err) {
        res.status(500).send(err);
    }
}); 

But the output is not nice as I need to have and this is what I see:但是输出并不像我需要的那样好,这就是我所看到的:

{
    "numberOfExperiences": [
        {
            "_id": null,
            "number": 4
        }
    ],
    "experiences": {
        "imageUrl": "https://via.placeholder.com/150",
        "_id": "5e26ff6d5be84a3aeeb2f7bb",
        "firstname": "Jakub",
        "surname": "Lemiszewski",
        "email": "jakub@email.com",
        "bio": "IT Geek",
        "title": "Senior Dev",
        "area": "Copenhagen",
        "username": "Jakos",
        "experience": [
            {
                "image": "",
                "createdAt": "2020-01-21T13:41:01.873Z",
                "updatedAt": "2020-01-21T13:41:01.873Z",
                "_id": "5e26ff6d5be84a3aeeb2f7bc",
                "title": "Senior Dev",
                "role": "Dev",
                "company": "ArosaDev",
                "startDate": "2018-12-03T23:00:00.000Z",
                "endDate": null,
                "description": "",
                "area": ""
            },

I need to have the output I showed in the beginning as per my requirments in my project and I'm getting issues to do so.我需要根据我在项目中的要求在开始时显示输出,并且我遇到了这样做的问题。

You can use the $size aggregation operator to get the count of experiences, and add it to the result using $addFields aggregation.您可以使用$size聚合运算符来获取经验计数,并使用$addFields聚合将其添加到结果中。

db.collection.aggregate([
  {
    $match: {
      "username": "Jakos"
    }
  },
  {
    $addFields: {
      "experiences_count": {
        $size: "$experience"
      }
    }
  },
  {
    $project: {
      experiences_count: 1,
      username: 1,
      experience: 1,
      _id: 0
    }
  }
])

Output:输出:

[
  {
    "experience": [
      {
        "_id": "5e26ff6d5be84a3aeeb2f7bc",
        "area": "",
        "company": "ArosaDev",
        "createdAt": "2020-01-21T13:41:01.873Z",
        "description": "",
        "endDate": null,
        "image": "",
        "role": "Dev",
        "startDate": "2018-12-03T23:00:00.000Z",
        "title": "Senior Dev",
        "updatedAt": "2020-01-21T13:41:01.873Z"
      },
      {
        "_id": "5e28791604718d7edb521c5b",
        "area": "Copenhagen",
        "company": "Mammamia",
        "createdAt": "2020-01-22T16:32:22.848Z",
        "description": "",
        "endDate": null,
        "image": "https://via.placeholder.com/150",
        "role": "Dev",
        "startDate": "2019-12-11T23:00:00.000Z",
        "updatedAt": "2020-01-22T16:32:22.848Z"
      }
    ],
    "experiences_count": 2,
    "username": "Jakos"
  }
]

Sample sandbox示例沙箱

So you can rewrite your code like this:所以你可以像这样重写你的代码:

experienceRouter.get("/:username", async (req, res) => {
  console.log(req.params.username);

  try {
    const profileWithExperiences = await Profiles.aggregate([
      { $match: { username: req.params.username } },
      {
        $addFields: {
          experiences_count: {
            $size: "$experience"
          }
        }
      },
      {
        $project: {
          experiences_count: 1,
          username: 1,
          experience: 1,
          _id: 0
        }
      }
    ]);

    if (profileWithExperiences.length > 0) {
      res.send({ profile: profileWithExperiences });
      //you can also return like this
      //res.send({ profile: profileWithExperiences[0] });
    } else {
      res.status(400).send("No profile found for username");
    }
  } catch (err) {
    console.log(err);
    res.status(500).send(err);
  }
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM