2012-04-18 91 views
1

Clojure的數據結構我有以下結構的MongoDB的文檔..MongoDB的文檔更新問題

{ 

    "key4" : 

     [ 
      {"k1":"v1", "k2":"va1", "k3":"value1"},   
      {"k1":"v2", "k2":"va2", "k4":"name"}, 
      {"k1":"v3", "k2":"va3"} 
     ] 
} 

當我更新與給定結構此文檔..

{ 

    "key4" : 

     [ 
      {"k1":"v1", "k3":"val1"},   
      {"k1":"v2", "k3":"val2"}, 
      {"k1":"v3", "k3":"val3"}, 
      {"k1":"v4", "k3":"val4"} 
     ] 
} 

我需要的輸出。

{ 

"key4" : 

     [ 
      {"k1":"v1", "k2":"va1", "k3":"val1"},   
      {"k1":"v2", "k2":"va2", "k3":"val2", "k4":"name"}, 
      {"k1":"v3", "k2":"va3", "k3":"val3"}, 
      {"k1":"v4", "k3":"val4"} 
     ] 
} 

這意味着如果新數組中存在'k1'的值,它應該合併唯一的對象數組變成新的。 我正在clojure地圖中實現這個結構。

+0

你還沒有提問?您是否在尋求如何實現「必要」輸出的建議,或者您是否已經創建了一個實現方案,並且遇到了具體問題? – sw1nn 2012-04-18 10:42:27

+0

是的,我正在尋找建議,以實現所需的輸出... – 2012-04-18 10:49:01

+0

如果更新缺少一個關鍵字(如「v2」),應該從答案中刪除,還是應該保持不變? – ivant 2012-04-18 12:24:24

回答

1

,你可以得到非常接近與merge-withmap組合,並merge

user> a 
{"key4" [{"k1" "v1", "k2" "va1", "k3" "value1"} 
     {"k1" "v2", "k2" "va2", "k4" "name"} 
     {"k1" "v3", "k2" "va3"}]} 
user> b 
{"key4" [{"k1" "v1", "k3" "val1"} 
     {"k1" "v2", "k3" "val2"} 
     {"k1" "v3", "k3" "val3"} 
     {"k1" "v4", "k3" "val4"}]} 
user> (merge-with #(map merge %1 %2) a b) 
{"key4" 
    ({"k1" "v1", "k2" "va1", "k3" "val1"} 
    {"k1" "v2", "k2" "va2", "k3" "val2", "k4" "name"} 
    {"k1" "v3", "k2" "va3", "k3" "val3"})} 
user> 

,那麼你需要從較長設置任何產品合併。

0

在你原來的問題中,你是否正在尋找一個主要針對Clojure或MongoDB答案的答案並不清楚。我將接受面向MongoDB的挑戰。

有這取決於你是否關心讀取或更新一些性能折衷

您提供的模式嵌入一個數組,是快速閱讀,但複雜的更新,需要的結果和隨後的第二次更新的檢查推/追加。

如果您希望利用MongoDB upsert獲取單個更新/插入請求,但您需要閱讀多個文檔,則可以取消嵌入/拼合模式。

下面請使用monger [com.novemberain/monger「1.0.0-beta4」]和Leiningen找到兩種方法的Clojure/monger代碼。

(ns FREE-10649-clojure.test.core 
    (:use [FREE-10649-clojure.core]) 
    (:use [clojure.test]) 
    (:require [monger.core] [monger.collection] [monger.query]) 
    (:use [monger.operators]) 
    (:import [org.bson.types ObjectId] [com.mongodb DB WriteConcern])) 

;; some operators are missing from monger 
(defmacro ^{:private true} defoperator 
    [operator] 
    (let [op# (str operator) 
     op-sym# (symbol op#)] 
     `(def ~op-sym# ~op#))) 

(defoperator $exists) 
(defoperator $mod) 
(defoperator $size) 
(defoperator $type) 
(defoperator $not) 

(deftest mytest 

    (def initial_doc { 
     "key4" [ 
       { "k1" "v1", "k2" "va1", "k3" "value1" } 
       { "k1" "v2", "k2" "va2", "k4" "name" } 
       { "k1" "v3", "k2" "va3" } 
      ] 
     } 
    ) 
    (def data_to_update { 
     "key4" [ 
       { "k1" "v1", "k3" "val1" } 
       { "k1" "v2", "k3" "val2" } 
       { "k1" "v3", "k3" "val3" } 
       { "k1" "v4", "k3" "val4" } 
      ] 
     } 
    ) 
    (def expected_doc { 
     "key4" [ 
       { "k1" "v1", "k2" "va1", "k3" "val1" } 
       { "k1" "v2", "k2" "va2", "k3" "val2", "k4" "name" } 
       { "k1" "v3", "k2" "va3", "k3" "val3" } 
       { "k1" "v4", "k3" "val4" } 
      ] 
     } 
    ) 

    (monger.core/connect!) 
    (monger.core/set-db! (monger.core/get-db "test")) 
    (def coll-name "free10649") 

    ;; user-supplied schema 
    (monger.collection/remove coll-name) 
    (is (= 0 (monger.collection/count coll-name))) 

    (monger.collection/insert coll-name initial_doc) 
    (is (= 1 (monger.collection/count coll-name))) 

    (doseq [outer_key (keys data_to_update)] 
     (def array_of_updates (data_to_update outer_key)) 
     (doseq [object_of_updates array_of_updates] 
     (def k1 "k1") 
     (def k3 "k3") 
     (def v1 (object_of_updates k1)) 
     (def v3 (object_of_updates k3)) 
     (def query { outer_key { $elemMatch { k1 v1 } } }) 
     (def update { $set { (str outer_key ".$." k3) v3 } }) 
     (monger.collection/update coll-name query update) 
     (if (false? (monger.result/updated-existing? (monger.core/get-last-error))) 
      (monger.collection/update coll-name { outer_key { $exists true } } { $push { outer_key object_of_updates } }) 
     ) 
    ) 
    ) 
    (prn "user-supplied-schema updated document") 
    (prn (monger.collection/find-maps coll-name)) 

    ;; flattened schema 
    (monger.collection/remove coll-name) 
    (is (= 0 (monger.collection/count coll-name))) 

    (doseq [outer_key (keys initial_doc)] 
     (def array_of_docs (initial_doc outer_key)) 
     (doseq [doc array_of_docs] 
     (monger.collection/insert coll-name (merge { outer_key true } doc)) 
    ) 
    ) 
    (prn "flattened-schema initial documents") 
    (prn (monger.collection/find-maps coll-name)) 

    (monger.collection/ensure-index coll-name { "key4" 1 "k1" 1 }) 
    ;;(monger.collection/explain (monger.collection/find coll-name { "key4" { $exists true } })) ;; missing explain in monger(?) 

    (doseq [outer_key (keys data_to_update)] 
     (def array_of_updates (data_to_update outer_key)) 
     (doseq [object_of_updates array_of_updates] 
     (def k1 "k1") 
     (def v1 (object_of_updates k1)) 
     (def query { outer_key { $exists true } k1 v1 }) 
     (def update { $set (merge { outer_key true } object_of_updates) }) 
     (monger.collection/update coll-name query update :upsert true) 
    ) 
    ) 

    (prn "flattened-schema updated documents") 
    (prn (monger.collection/find-maps coll-name)) 
)