【问题标题】:Populate field in an array of objects MongoDB and Mongoose在 MongoDB 和 Mongoose 对象数组中填充字段
【发布时间】:2021-07-09 16:42:39
【问题描述】:

我正在为我的网站建立一个评论系统。我为这篇文章创建了这个架构,它是 cmets:

let articleSchema = mongoose.Schema({

  language: {
    type: String,
    default: "english"
  },
  slug: {
    type: String,
    required: true
  },
  image: {
    type: String,
    required: true
  },
  title: {
    type: String,
    required: true
  },
  tags: {
    type: [String],
    required: true
  },
  author: {
    type: mongoose.Schema.Types.ObjectId,
    ref: "User",
    required: true
  },
  date: {
    type: Date,
    default: Date.now()
  },
  description: {
    type: String,
    required: false
  },
  body: {
    type: String,
    required: true
  },

  translation: [
    {
      language: {
        type: String,
        required: true
      },
      title: {
        type: String,
        required: true
      },
      tags: {
        type: [String],
        required: true
      },
      description: {
        type: String,
        required: false
      },
      body: {
        type: String,
        required: true
      }
    }
  ],
  comments: [{
    author: {
      type: mongoose.Schema.Types.ObjectId,
      ref: "User"
    },
    date: {
      type: Date,
      default: Date.now()
    },
    body: {
      type: String,
      required: true
    }
  }]
});

现在我要做的是填充每个评论作者字段。

假设这是带有评论的文章:

{
  "comments": [
   {
    "author": "5f71d3b575f9f800943903af",
    "date": "some date here",
    "body": "comment body"
   }
  ]
}

现在我在填充完所有这些后想要得到的是:

{
  "comments": [
   {
    "author": {
      "username": "Username",
      "avatar": "fox"
    },
    "date": "some date here",
    "body": "comment body"
   }
  ]
}

我该怎么做?

这是我当前的代码:


router.get('/article/:id', async (req, res) => {
  const { id: articleId } = req.params;

  const lang = req.i18n.language;
  const langName = new Intl.DisplayNames(['en'], { type: "language" }).of(lang).toLowerCase();

  try {

    console.log(langName);

    if (req.i18n.language === "en") {
      var article = await Article.findById(articleId)
        .populate([
          {path:'comments.author', select:'+photo +username'},
          {path:'author', select:'+photo +username'}
        ])
        .select("title image tags author date description body comments");
    } else {

      var article = await Article
        .aggregate([
          {
            $match: {
              "_id": ObjectId(articleId)
            }
          }, {
            $unwind: "$translation"
          }, {
            $match: {
              "translation.language": langName
            }
          }, {
            $group: {
              _id: "$_id",
              image: { $first: "$image" },
              title: { $first: "$translation.title" },
              tags: { $first: "$translation.tags" },
              author: { $first: "$author" },
              date: { $first: "$date" },
              description: { $first: "$translation.description" },
              body: { $first: "$translation.body" },
              comments: { $first: "$comments" }
            }
          },
          {
            $lookup: {
              from: "users",
              localField: "author",
              foreignField: "_id",
              as: "author"
            }
          },
          {
            $unwind: {
              path: "$author"
            }
          },
          { ///////////////////// Here I need to populate the comment author. How can I do it?
            $lookup: {
              from: "users",
              localField: "comments.author",
              foreignField: "_id",
              as: "comments.author"
            }
          },
          {
            $unwind: {
              path: "$comments.author"
            }
          },
          {
            $project: {
              image: 1,
              title: 1,
              tags: 1,
              date: 1,
              description: 1,
              body: 1,
              // comments: 1,
              "comments.date": 1,
              "comments.body": 1,
              "comments.author.username": 1,
              "comments.author.avatar": 1,
              "author.username": 1,
              "author.avatar": 1
            }
          }
        ], function(err, result) {
          console.log(err)
          return result;
        });
      
      console.log(article[0].comments[0]);
      console.log(article);
    }

    if (!article) throw new Error();
  } catch {
    return res.status(404).render('errors/404');
  }


  res.render('articles/article', {
    article: article[0]
  });
});

【问题讨论】:

    标签: node.js mongodb express mongoose mongoose-populate


    【解决方案1】:

    经过一番挖掘,我想出了这个解决方案:

    router.get('/article/:id', async (req, res) => {
      const { id: articleId } = req.params;
    
      const lang = req.i18n.language;
      const langName = new Intl.DisplayNames(['en'], { type: "language" }).of(lang).toLowerCase();
    
      try {
    
        if (req.i18n.language === "en") {
          var article = await Article.findById(articleId)
            .populate([
              {path:'comments.author', select:'+photo +username'},
              {path:'author', select:'+photo +username'}
            ])
            .select("title image tags author date description body comments");
        } else {
    
          var article = await Article
            .aggregate([
              {
                $match: {
                  "_id": ObjectId(articleId)
                }
              }, {
                $unwind: "$translation"
              }, {
                $match: {
                  "translation.language": langName
                }
              },
              {
                $lookup: {
                  from: "users",
                  localField: "author",
                  foreignField: "_id",
                  as: "author"
                }
              },
              {
                $unwind: {
                  path: "$author"
                }
              },
              {
                $unwind: {
                  path: "$comments"
                }
              },
              {
                $lookup: {
                  from: "users",
                  localField: "comments.author",
                  foreignField: "_id",
                  as: "comments.author"
                }
              },
              {
                $group: {
                  _id: "$_id",
                  root: { $mergeObjects: '$$ROOT' },
                  image: { $first: "$image" },
                  title: { $first: "$translation.title" },
                  tags: { $first: "$translation.tags" },
                  author: { $first: "$author" },
                  date: { $first: "$date" },
                  description: { $first: "$translation.description" },
                  body: { $first: "$translation.body" },
                  comments: { $push: "$comments" }
                }
              },
              {
                $project: {
                  image: 1,
                  title: 1,
                  tags: 1,
                  date: 1,
                  description: 1,
                  body: 1,
                  "comments.date": 1,
                  "comments.body": 1,
                  "comments.author.username": 1,
                  "comments.author.avatar": 1,
                  "author.username": 1,
                  "author.avatar": 1
                }
              }
            ]);
          
        }
    
        if (!article) throw new Error();
      } catch {
        return res.status(404).render('errors/404');
      }
    
    
      res.render('articles/article', {
        article: article[0]
      });
    });
    

    【讨论】:

      猜你喜欢
      • 2022-01-24
      • 2016-01-19
      • 2021-04-19
      • 2022-11-10
      • 1970-01-01
      • 2019-10-19
      • 2016-09-15
      • 2017-10-26
      • 2019-11-24
      相关资源
      最近更新 更多