2016-04-15 21 views
3

考慮下面的文檔中的子文檔的數組:

{ 
    "item1" : [ 
     { 
      "a" : 1, 
      "b" : 2 
     } 
    ], 
    "item2" : [ "a", "b" ] 
} 

下面的查詢:

db.test.aggregate([ 
    { "$project": { "items": { "$setIntersection": [ "$item1", "$item2" ] } }} 
]) 

返回預期的結果:

{ "_id" : ObjectId("5710785387756a4a75cbe0d1"), "a" : [ ] } 

如果文檔看起來像這樣:

{ "item2" : [ "a", "b" ] } 

然後:

db.test.aggregate([ { "$project": { 
    "a": { "$setIntersection": [ "$item2", [ "a" ] ] } } } 
]) 

產量:

{ "_id" : ObjectId("5710785387756a4a75cbe0d1"), "a" : [ "a" ] } 

db.test.aggregate([   
    { "$project": { "items": { "$setIntersection": [ "$item2", [ { "a" : 1, "b" : 2 } ] ] } } } 
]) 

失敗:

「ERRMSG」: 「字段包含不允許$表達式的內部」

和:

db.test.aggregate([ { "$project": { 
    "items": { "$setIntersection": [ "$item2", [ { "a": "b" } ] ] } } } 
]) 

失敗:

「ERRMSG」:「FieldPath會 'B'不以$開頭「

使這項工作的唯一方法是使用$literal運營商。

我們爲什麼要使用$literal運營商如果$setIntersection參數是在文檔中的子文檔的陣列,而不是一個

回答

0

這似乎是在MongoDB中3.2兼容性的變化因此是預期的行爲如在Aggregation Compatibility Changes in MongoDB 3.2提到:

數組元素作爲聚合管線文字不再處理。相反,數組中的每個元素現在都被解析爲一個表達式。要將元素視爲文字而不是表達式,請使用$literal運算符創建文字值。

1

這似乎是MongoDB 3.2的一個工件,它包含了一個允許在直接插入文檔屬性時插入數組的變化。

例如,對於一個文件,如:

{ "a": 1, "b": 2, "c": 3, "d": 4 } 

然後你「現在」允許譜寫那些元件的陣列內,如:

db.collection.aggregate([ 
    { "$project": { 
     "array": [ 
      { "field1": "$a", "field2": "$b" }, 
      { "field1": "$c", "field2": "$d" } 
     ] 
    }} 
]) 

在以前的版本(在此情況MongoDB 2.6),您需要使用此$map表達式:

db.collection.aggregate([ 
    { "$project": { 
     "array": { 
      "$map": { 
       "input": ["A","B"], 
       "as": "el", 
       "in": { 
        "$cond": { 
         "if": { "$eq": [ "$$el", "A" ] }, 
         "then": { "field1": "$a", "field2": "$b" }, 
         "else": { "field1": "$c", "field2": "$c" } 
        } 
       } 
      } 
     } 
    }} 
]) 

或者在之前的版本中,使用$unwind$group的東西有點長,但是與將其他數據轉換爲「源」數組的基本原理相同。主要的一點是MongoDB 3.2中允許的符號更改,否則在之前的版本中會出現「錯誤」。

因此,在以前的版本,說MongoDB的2.6.x的,是支持$setIntersection那麼下面的作品就好了,因爲所有的值被認爲是「文字」除非實際引用數組出現在文檔中:

db.collection.aggregate([ 
    { "$project": { 
    "a": { 
     "$setIntersection": [ 
     [{"a": 1}], 
     [{"a": 1}] 
     ] 
    } 
    }} 
]) 

當然條件是"collection"作爲一個集合實際上在它的東西。

但由於MongoDB的3.2允許「內插陣列」不同的語法,它現在預計「右側」,以評估從文檔或者其他有效表達的性質。所以,現在的$literal語法要求:

db.collection.aggregate([ 
    { "$project": { 
    "a": { 
     "$setIntersection": [ 
     { "$literal": [{"a": 1}] }, 
     { "$literal": [{"a": 1}] } 
     ] 
    } 
    }} 
]) 

這通常歸結爲說「你不能有你的蛋糕,吃它太」。 「新」語法允許你以一種很好的方式用「插值」表達數組內容,而不訴諸其他表達式將內容「脅迫」成數組形式。

這樣做的後果是,這樣的表達現在期望「值」解析爲屬性或表達式,而不是直接被認爲是「文字」,並且您的意思是這樣,你現在是需要使用$literal運算符來表示該值。

所以這其實是在版本之間可以使用的語法是「破」的變化。但大多數人都應該輕鬆地生活。

相關問題