【问题标题】:Create Mongoose Find and populate from multiple tables with property set创建 Mongoose 从具有属性集的多个表中查找和填充
【发布时间】:2020-03-14 14:47:59
【问题描述】:

对于 Mongoose 的帮助,我将不胜感激。我有 3 个表:(用户)用户表,(动物)动物表和表 AnimalComments。所以(AnimalComments)表参考用户和动物。

const schemaComment = new mongoose.Schema({
        userRef: {
            type: mongoose.Schema.Types.ObjectId,
            ref: 'User'
        },
        animalRef: {
            type: mongoose.Schema.Types.ObjectId,
            ref: 'Animal'
        },
        content: {
            type: String
        }
    });

const schemaAnimal = new mongoose.Schema({
    name: {
        type: String
    },
    isCommentedByMe: {
        type   : Boolean,
        default: false
    },
    commentCount: {
        type   : Number,
        default: 0
    }
});

我想要什么:我有动物。用户可以为动物添加评论。当用户评论动物时,他的评论被添加到表 AnimalComments 中,其中存储了 userRef (userId)、animalRef (animalId) 和用户评论文本。然后在请求响应中,我想返回表 Animals 中的所有动物,但我需要根据表 AnimalComments 中的值更新属性 commentCount 和 isCommentedByMe。

Table Animals 的回应:

{
    "animals": [
        {
            "isCommentedByMe": false,
            "commentCount": 0,
            "name": "Jessica",
            "userRef": {
                "id": "5dc9bdf3dd5cae00177e184d"
            },
            "id": "5dcedd48368e9800176f2ef3"
        }
    ]
}

来自表用户的回应:

{
    "users": [
        {
            "name": "Jony Cash",
            "id": "5dc9bdf3dd5cae00177e184d"
        }
    ]
}

AnimalComments 表的回复:

{
    "comments": [
        {
            "userRef": "5dc9bdf3dd5cae00177e184d",
            "animalRef": "5dcedd48368e9800176f2ef3",
             "content": "Sample text"
        }
    ]
}

我想要例如结果:

{
    "animals": [
        {
            "isCommentedByMe": true, 
            "commentCount": 4, 
            "name": "Jessica",
            "userRef": {
                "id": "5dc9bdf3dd5cae00177e184d"
            },
            "id": "5dcedd48368e9800176f2ef3"
        }
    ]
}

【问题讨论】:

  • 如果你能给出预期的结果,就很容易理解你想要什么。
  • 我认为您的数据模型有点错误。根据已经存储的内容设置一个属性并不是一个好主意。无需将allLikeCount 设置为所有评论喜欢的计数,只需在每次需要时汇总评论喜欢。这将确保数据永远不会不同步,并始终提供最准确和最新的结果。
  • @SuleymanSah 我更新了我的问题应该更清楚
  • @chrispytoes 我更新了我的问题应该更清楚
  • 请提供一些示例输入文件,以及预期的输出文件

标签: node.js database mongodb mongoose populate


【解决方案1】:

您不需要在动物模式中保留 isCommentedByMe 和 commentCount 字段。

而且您需要能够从您的动物那里访问 cmets。但在动物图式中,没有领域可以建立这种联系。所以我们需要使用虚拟人口。

所以你的动物图式一定是这样的:

const schemaAnimal = new mongoose.Schema(
  {
    name: {
      type: String
    }
  },
  {
    toJSON: { virtuals: true },
    toObject: { virtuals: true }
  }
);

// Virtual populate
schemaAnimal.virtual("comments", {
  ref: "Comment",   //must be changed to the name you used for Comment model.
  foreignField: "animalRef",
  localField: "_id"
});

现在,我们可以使用以下代码来填充 cmets。

router.get("/animals", async (req, res) => {
  const animals = await Animal.find({}).populate("comments");
  res.send(animals);
});

这会给你这样的结果:

[
    {
        "_id": "5dd66c73069f88614c12b394",
        "name": "Animal 1",
        "__v": 0,
        "comments": [
            {
                "_id": "5dd66cfd069f88614c12b39a",
                "userRef": "5dd66b54c5195127ec5a1b82",
                "animalRef": "5dd66c73069f88614c12b394",
                "content": "User 1 - Animal 1",
                "__v": 0
            },
            {
                "_id": "5dd66d30069f88614c12b39d",
                "userRef": "5dd66b71c5195127ec5a1b83",
                "animalRef": "5dd66c73069f88614c12b394",
                "content": "User 2 - Animal 1",
                "__v": 0
            }
        ],
        "id": "5dd66c73069f88614c12b394"
    },
    {
        "_id": "5dd66c7d069f88614c12b395",
        "name": "Animal 2",
        "__v": 0,
        "comments": [
            {
                "_id": "5dd66d09069f88614c12b39b",
                "userRef": "5dd66b54c5195127ec5a1b82",
                "animalRef": "5dd66c7d069f88614c12b395",
                "content": "User 1 - Animal 2",
                "__v": 0
            }
        ],
        "id": "5dd66c7d069f88614c12b395"
    },
    {
        "_id": "5dd66c88069f88614c12b396",
        "name": "Animal 3",
        "__v": 0,
        "comments": [
            {
                "_id": "5dd66d46069f88614c12b39e",
                "userRef": "5dd66b71c5195127ec5a1b83",
                "animalRef": "5dd66c88069f88614c12b396",
                "content": "User 2 - Animal 3",
                "__v": 0
            }
        ],
        "id": "5dd66c88069f88614c12b396"
    }
]

要将此结果转换为您想要的结果,我们可以像这样使用 map:

请注意,您需要将loggedInUserId 变量设置为登录用户的ID。

router.get("/animals", async (req, res) => {
  const loggedInUserId = "5dd66b54c5195127ec5a1b82";

  const animals = await Animal.find({}).populate("comments");

  const result = animals.map(animal => {
    return {
      id: animal._id,
      name: animal.name,
      isCommentedByMe:
        animal.comments.filter(c => c.userRef.toString() === loggedInUserId)
          .length > 0,
      commentCount: animal.comments.length
    };
  });

  res.send(result);
});

结果会是这样的:

[
    {
        "id": "5dd66c73069f88614c12b394",
        "name": "Animal 1",
        "isCommentedByMe": true,
        "commentCount": 2
    },
    {
        "id": "5dd66c7d069f88614c12b395",
        "name": "Animal 2",
        "isCommentedByMe": true,
        "commentCount": 1
    },
    {
        "id": "5dd66c88069f88614c12b396",
        "name": "Animal 3",
        "isCommentedByMe": false,
        "commentCount": 1
    }
]

而cmets中问题的答案是:(如何引用User)

  const animals = await Animal.find({}).populate({
    path: "comments",
    model: Comment,
    populate: [
      {
        path: "userRef",
        model: User
      }
    ]
  });

这将为您提供这样的 userRef:

[
    {
        "_id": "5dd66c73069f88614c12b394",
        "name": "Animal 1",
        "__v": 0,
        "comments": [
            {
                "_id": "5dd66cfd069f88614c12b39a",
                "userRef": {
                    "_id": "5dd66b54c5195127ec5a1b82",
                    "name": "User 1",
                    "__v": 0
                },
                "animalRef": "5dd66c73069f88614c12b394",
                "content": "User 1 - Animal 1",
                "__v": 0
            },
            {
                "_id": "5dd66d30069f88614c12b39d",
                "userRef": {
                    "_id": "5dd66b71c5195127ec5a1b83",
                    "name": "User 2",
                    "__v": 0
                },
                "animalRef": "5dd66c73069f88614c12b394",
                "content": "User 2 - Animal 1",
                "__v": 0
            }
        ],
        "id": "5dd66c73069f88614c12b394"
    },
    {
        "_id": "5dd66c7d069f88614c12b395",
        "name": "Animal 2",
        "__v": 0,
        "comments": [
            {
                "_id": "5dd66d09069f88614c12b39b",
                "userRef": {
                    "_id": "5dd66b54c5195127ec5a1b82",
                    "name": "User 1",
                    "__v": 0
                },
                "animalRef": "5dd66c7d069f88614c12b395",
                "content": "User 1 - Animal 2",
                "__v": 0
            }
        ],
        "id": "5dd66c7d069f88614c12b395"
    },
    {
        "_id": "5dd66c88069f88614c12b396",
        "name": "Animal 3",
        "__v": 0,
        "comments": [
            {
                "_id": "5dd66d46069f88614c12b39e",
                "userRef": {
                    "_id": "5dd66b71c5195127ec5a1b83",
                    "name": "User 2",
                    "__v": 0
                },
                "animalRef": "5dd66c88069f88614c12b396",
                "content": "User 2 - Animal 3",
                "__v": 0
            }
        ],
        "id": "5dd66c88069f88614c12b396"
    }
]

【讨论】:

  • 谢谢,我的最后一个问题是。是否可以将填充添加到虚拟填充?现在的响应是 { "_id": "5dd66d09069f88614c12b39b", "userRef": "5dd66b54c5195127ec5a1b82", "animalRef": "5dd66c7d069f88614c12b395", "content": "User 1 - Animal 2" } 我想要 { "_id": "5dd66 , "userRef": { 这里举个例子完整的对象不仅仅是 ID } "animalRef": "5dd66c7d069f88614c12b395", "content": "..." }
  • @pavol.franek 是的,有可能,请检查答案末尾的更新。
  • 非常感谢您抽出宝贵的时间。
猜你喜欢
  • 1970-01-01
  • 2019-05-26
  • 2016-09-03
  • 2020-09-10
  • 2017-03-30
  • 2016-05-26
  • 1970-01-01
  • 2012-01-04
  • 2019-12-03
相关资源
最近更新 更多