在 mongoose 中填充嵌套数组 - Node.js

Posted

技术标签:

【中文标题】在 mongoose 中填充嵌套数组 - Node.js【英文标题】:Populate nested array in mongoose - Node.js 【发布时间】:2016-10-12 05:01:26 【问题描述】:

这些是我的模式(主题是父主题,包含“思想”列表):

var TopicSchema = new mongoose.Schema(
  title:  type: String, unique: true ,
  category: String,
  thoughts: [ThoughtSchema]
, 
  timestamps: true,
  toObject: virtuals: true,
  toJSON: virtuals: true
);

var ThoughtSchema = new mongoose.Schema(
  text: String,
  author: type: mongoose.Schema.Types.ObjectId, ref: 'User',
  votes:[
    _id:false,
    voter: type: mongoose.Schema.Types.ObjectId, ref: 'User',
    up: Boolean,
    date: type: Date, default: Date.now
  ]
, 
  timestamps: true,
  toObject: virtuals: true,
  toJSON: virtuals: true
);

....

我正在尝试阅读该想法的作者并像这样更改我的 get Topic api:

...
  var cursor = Topic.find(query).populate(
    path: 'thoughts',
    populate: 
      path: 'author',
      model: 'User'
    
  ).sort(popularity : -1, date: -1);

  return cursor.exec()
    .then(respondWithResult(res))
    .catch(handleError(res));
...

但是作者是空的..我也没有在控制台中得到任何错误。这里有什么问题?

编辑:实际上我不需要 Thought 作为模式,它在数据库中没有自己的集合。它将保存在主题中。但是为了将 timestamps 选项与想法一起使用,我需要将其内容提取到新的本地模式 ThoughtSchema。但是我现在直接在主题的想法数组中定义了thinkSchema的内容,还是不行。

Edit2:这是执行前的光标对象。不幸的是,我无法在 Webstorm 中调试,这是来自节点检查器的屏幕截图:

【问题讨论】:

@Theodore 的答案对我来说是正确的:query 的内容是什么?你有select吗? 我上传了光标对象执行前的内容截图 【参考方案1】:

这些是架构:

var TopicSchema = new mongoose.Schema(
  title:  type: String, unique: true ,
  category: String,
  thoughts: [ThoughtSchema]
, 
  timestamps: true,
  toObject: virtuals: true,
  toJSON: virtuals: true
);

var ThoughtSchema = new mongoose.Schema(
  text: String,
  author: type: mongoose.Schema.Types.ObjectId, ref: 'User',
  votes:[
    _id:false,
    voter: type: mongoose.Schema.Types.ObjectId, ref: 'User',
    up: Boolean,
    date: type: Date, default: Date.now
  ]
, 
  timestamps: true,
  toObject: virtuals: true,
  toJSON: virtuals: true
);

您是否尝试过聚合而不是填充。聚合使用$lookup 填充嵌入数据变得更加容易。试试下面的代码。

更新

Topic.aggregate([$unwind: "$thoughts", $lookup: from: 'users', localField: 'thoughts.author', foreignField: '_id', as: 'thoughts.author',$sort:popularity : -1, date: -1],function(err,topics)
 console.log(topics) // `topics` is a cursor.
 // Perform Other operations here.
)

解释

$unwind:从输入文档中解构一个数组字段,为每个元素输出一个文档。

$lookup:$lookup 阶段在输入文档中的字段与“加入”集合的文档中的字段之间进行相等匹配。查找完成了人口的工作。

$lookup 的工作方式类似于

来自:这表示需要从哪个集合中填充数据。(在这种情况下为users)。

localField :这是需要填充的本地字段。 (在这种情况下为thoughts.author)。

foreignField :这是集合中存在的外部字段,需要从中填充数据(在这种情况下,users 集合中的_id 字段)。

as :这是您希望将连接值显示为的字段。 (这会将thoughts.author 的ID 投影为thoughts.author 文档)。

希望这行得通。

【讨论】:

“你尝试过聚合而不是填充吗?”对不起..但据我所知,聚合通常与“匹配”而不是“查找”一起使用..所以它不是填充的替代方法,但是'找到'我想..所以我不知道如何将它集成到我的代码中..聚合是否还返回一个游标对象,必须在之后执行?您能否更新我在问题中的第二个代码并写下所有行?【参考方案2】:

您是否尝试过使用Model.populate?

Topic.find(query).populate('thoughts')
.sort(popularity : -1, date: -1)
.exec(function(err, docs) 
   // Multiple population per level
  if(err) return callback(err);
  Thought.populate(docs, 
    path: 'thoughts.author',
    model: 'User'
  ,
  function(err, populatedDocs) 
    if(err) return callback(err);
    console.log(populatedDocs);
  );
);

更新: 您可以像这样尝试deep populate:

Topic.find(query).populate(
  path: 'thoughts',
  populate: 
    path: 'author',
    model: 'User'
  
)
.sort(popularity : -1, date: -1)
.exec(function(err, docs) 
  if(err) return callback(err);
  console.log(docs);
);

【讨论】:

'Thought' 未导出。我也不知道如何导出多个模式...这是唯一的导出行:export default mongoose.model('Topic', TopicSchema); 您不需要将其导出,因为您将其用作嵌入式架构。在那种情况下,我确认@Theodore 的答案应该有效。你检查过你的数据库吗?对author 的引用是否正确保存? 是的.. 作者字段具有用户的 id。但我不知何故无法在 webstorm 中调试服务器端代码以查看查询的外观。我将在接下来的几天尝试调试。但是关于“思想”架构..当我按照您的建议使用 Thought.populate 时,无法编译应用程序.. 终端中出现“思想未定义”之类的东西 我建议您可以尝试另一个选项。 这正是我在我的问题中所写的【参考方案3】:

怎么样

Topic.find(query).populate('thoughts')
.sort(popularity : -1, date: -1)
.exec(function(err, docs) 
   // Multiple population per level
  if(err) return callback(err);
  Topic.populate(docs, 
    path: 'thoughts.author',
    model: 'User'
  ,
  function(err, populatedDocs) 
    if(err) return callback(err);
    console.log(populatedDocs);
  );
);

【讨论】:

以上是关于在 mongoose 中填充嵌套数组 - Node.js的主要内容,如果未能解决你的问题,请参考以下文章

mongoose#populate 在数组内的嵌套对象中返回 null

试图在 mongoose 中填充一个嵌套数组,抛出一个看似无关的 CastError,我不明白为啥

Mongoose:填充嵌套的 id 数组

MongoDB Mongoose 聚合查询深度嵌套数组删除空结果并填充引用

如何使用 Node.js 和 Mongoose 将对象添加到嵌套数组

填充嵌套数组的无引用对象