2014-09-26 72 views
0
嵌套很深的文檔中更新字段

有問題的MongoDB的文檔結構如下:MongoDB中

{ 
"_id": ObjectId("54247a68fab6b6775d000062"), 
"owner": "1", 
"version": "Version 1", 
"name": "Test20", 
"u_at": ISODate("2014-09-25T20:26:16.140Z"), 
"c_at": ISODate("2014-09-25T20:26:16.140Z"), 
"canvases": [ 
    { 
     "_id": ObjectId("54247a68fab6b6775d000063"), 
     "nodes": [ 
      { 
       "_id": ObjectId("54247a68fab6b6775d000060"), 
       "filePathTemplate": "LETSDOEMAIL" 
      }, 
      { 
       "_id": ObjectId("54247a68fab6b6775d000061"), 
       "filePathTemplate": "LETSDOFACEBOOK" 
      } 
     ] 
    } 
    ] 
} 

我有兩件事情主要是掙扎:

  1. 搜索特定節點並且只返回結果中的節點。以下是我目前使用的查詢(瀏覽所有相關SO問題後):

    db.getCollection("coll").find({_id: ObjectId("54247a68fab6b6775d000062")}, {canvases:{$elemMatch:{nodes:{$elemMatch:{_id: ObjectId("54247a68fab6b6775d000060")}}}}})

    但是這給後面的帆布,包含節點搜索,而不是節點。

    { 
    "_id": ObjectId("54247a68fab6b6775d000062"), 
    "canvases": [ 
        { 
        "_id": ObjectId("54247a68fab6b6775d000063"), 
        "nodes": [ 
         { 
          "_id": ObjectId("54247a68fab6b6775d000060"), 
          "filePathTemplate": "LETSDOEMAIL" 
         }, 
         { 
          "_id": ObjectId("54247a68fab6b6775d000061"), 
          "filePathTemplate": "LETSDOFACEBOOK" 
         } 
         ] 
        } 
        ] 
    } 
    
  2. 由於上述問題,更新節點文檔中的字段也是一個問題。這是我從其他SO問題,但都無濟於事了查詢:

    db.getCollection("coll").update({canvases: {$elemMatch:{nodes:{$elemMatch:{_id: ObjectId("54247a68fab6b6775d000060")}}}}}, {$set: {"canvases.$.nodes.$.filePathTemplate": "21"}})

任何幫助,將不勝感激。

+0

那麼在這種情況下,因爲我使用[elemMatch投影](http://docs.mongodb.org/manual/reference/operator/projection/elemMatch/),' find()'返回包含匹配節點的畫布,而不是整個文檔。 – shardnit 2014-09-26 16:45:56

回答

0

問題1:

只有在.find(arg1, arg2)所述第二參數的第一$elemMatch是有效的定位陣列的元件,即,的canvases僅一個元件可被定位,排除nodes'。所以.find()在我看來做這種任務是不合適的。
但我認爲你可以達到通過以下方法目標:

db.coll.aggregate([ { 
    $match : { 
     _id : ObjectId("54247a68fab6b6775d000062") 
    } 
}, { 
    $redact : { 
     $cond : [ { 
      $or : [ { 
       $gt : [ "$canvases", [] ] 
      }, { 
       $gt : [ "$nodes", [] ] 
      }, { 
       $eq : [ "$_id", ObjectId("54247a68fab6b6775d000060") ] 
      } ] 
     }, "$$DESCEND", "$$PRUNE" ] 
    } 
} ]); 

問題2:

  • 陣地操作$不能嵌套數組使用;
  • 所以當你在一個數組後面使用$時,所有其餘的路徑必須是「固定的」。這意味着如果$後面有嵌套數組,則必須明確寫出其索引以指出要更新哪個元素。

假設這個集合的所有文檔級別中的所有_id都是唯一的。
下面,供大家參考代碼:

var searchKey = ObjectId("54247a68fab6b6775d000060"); 
var filePathTemplate = "21"; 

db.getCollection("coll").find({ 
    canvases : { 
     $elemMatch : { 
      nodes : { 
       $elemMatch : { 
        _id : searchKey 
       } 
      } 
     } 
    } 
}, { 
    "canvases.$" : 1 
}).forEach(function(doc) { 
    // We need to find out the index of that sub-document which is required to 
    // updated in nodes, because nodes is probably very big. 
    var i = 0; 
    var nodes = doc.canvases[0].nodes; // Only one element in canvases from abover query. 
    for (; i < nodes.length && nodes[i]._id.str != searchKey.str; ++i); 
    var key = "canvases.$.nodes." + i + ".filePathTemplate"; // Only one "$" can be used. 
    var updateNodePart = {}; 
    updateNodePart[key] = filePathTemplate; 

    db.getCollection("coll").update({ 
     canvases : { 
      $elemMatch : { 
       nodes : { 
        $elemMatch : { 
         _id : searchKey 
        } 
       } 
      } 
     } 
    }, { 
     $set : updateNodePart 
    }); 
}); 
+0

我想你是對的。我也嘗試了很多組合,但似乎沒有辦法將元素錨定在深度嵌套數組中。 – shardnit 2014-09-29 15:38:54