如何通过MongooseJS操作/删除MongoDB中的子文档?

时间:2015-07-14 14:05:12

标签: mongodb mongoose

我有以下架构:

//define suberSchema
var suberSchema = new Schema({
    _id: {
        type: Schema.Types.ObjectId,
        required: true
    },
    constraints: [constraintSchema]
});

//define spaceInfoSchema
var spaceInfoSchema = new Schema({
    spaceName: String,
    subers: [suberSchema],
    _id: {
    type: Schema.Types.ObjectId,
    required: true
   }
});

我想操纵/获取子文件,但是当我使用下面的代码时,它只是操作parentdocs。

  • 这将返回包含所有subers的数组。我该怎么做才能获得具有指定ID的suber?

spaceInfoModel.find({"_id": spaceId,"subers._id": userId}, "subers", callback);

  • 这将删除整个文档。我该怎么做才能删除具有指定ID的suber?

spaceInfoModel.remove({"_id": spaceId,"subers._id": userId}, callback);

提前致谢。

2 个答案:

答案 0 :(得分:1)

find()将始终从调用它的集合中返回文档。在您的示例中spaceInfoModel。查询:spaceInfoModel.find({"_id": spaceId,"subers._id": userId}, "subers", callback);正在检查spaceInfoModel集合中与spaceId的ID匹配的文档,并且还有一个ID为{{1}的子文档}。如果找到任何匹配的文档,它们将作为数组返回给回调函数。

此时,您可以使用辅助函数id()来检索子文档:

userId

然而,返回所有子文档会产生令人遗憾的副作用,因此您可以将其修剪为1。一种更有效的方法是让Mongo在返回父文档之前削减子doc数组。 $elemMatch投影运算符可用于执行此操作。

// Using findOne but you could easily match this with findById as well
spaceInfoModel.findOne({"_id": spaceId,"subers._id": userId}, 'subers').exec().then(function(spaceInfo) {
  // spaceInfo.subers is the entire sub-doc array
  return spaceInfo.subers.id(userId);
}).then(function(suber) {
  // do something with the suber
}).then(null, function(err) { ... });

除此之外,您还可以探索使用聚合管道来展开文档子文档,但我不相信使用spaceInfoModel.findById(spaceId).select({subers: {$elemMatch: {_id: userId}}}).exec().then(function(spaceInfo) { // spaceInfo.subers is an array of only the matching sub-doc return spaceInfo.subers.id(userId); }).then(function(suber) { // do something with the suber }).then(null, function(err) { ... }); 会有很多好处。

要删除子文档,可以采用类似的方式。第一种方法需要检索整个数组,然后使用pull()在本地修改它,然后再将其保存回MonogoDB。

elemMatch()

同样,这可以直接在MongoDB服务器上更有效地完成。

spaceInfoModel.findOne({"_id": spaceId,"subers._id": userId}, 'subers').exec().then(function(spaceInfo) {
  // spaceInfo.subers is the entire sub-doc array
  // remove the matching ID
  spaceInfo.subers.pull({_id: userId});

  // Commit to mongoDB
  return spaceInfo.save();
}).then(function() {
  ...
}).then(null, function(err) { ... });

注意: spaceInfoModel.findByIdAndUpdate(spaceId, {$pull: {subers: {_id: userId}}}).select({subers: {$elemMatch: {_id: userId}}}).exec().then(function(spaceInfo) { // spaceInfo.subers is an array of only the matching sub-doc // the original doc is returned with the removed sub-doc on success return spaceInfo.subers.id(userId); }).then(function(suber) { // do something with the suber }).then(null, function(err) { ... }); 仅用于返回已删除的子文档。如果您不在乎,可以将其简化为:

$elemMatch

答案 1 :(得分:0)

你必须这样做

spaceInfoModel.aggregate({$match
{
    "_id": spaceId,
}},{$unwind:'$subers"}, {$match:{
    "subers._id": userId
}}, "subers", callback);

你得到这样的结果

[{_id: '****',subers: {_id: '',constraints: [some data]}}]

删除

spaceInfoModel.update(
{
    "_id": spaceId,
      "subers._id": userId
},{$pull:{subers:{_id:userId}}},callback)