2010-06-28 3 views
5

저는 MongoDB 초보자이며 upsert 및 list와 관련된 업데이트 명령을 작성하는 방법을 묻고 싶습니다. , 여행이 이미 존재하지 않는 경우 당신은 여행의 이름과 현재 위치 MongoDB - upsert 관련 목록

  • 를 제공

    • : 것을

      {"_id" : ObjectId("4c28f62cbf8544c60506f11d"), 
      "some_other_data":"goes here", 
      "trips": [ 
          {"name": "2010-05-10", 
          "loc": [{"lat":21.321231, "lng": 16.8783234, "updated_at": "Mon May 10 2010 15:24:35"}, 
           {"lat":21.321231, "lng": 16.8783234, "updated_at": "Mon May 10 2010 15:24:24"}] 
          }, 
          {"name": "2010-05-08", 
          "loc": [{"lat":21.324239, "lng": 16.8735234, "updated_at": "Mon May 8 2010 11:18:05"}, 
           {"lat":21.311234, "lng": 16.8743271, "updated_at": "Mon May 8 2010 11:17:55"}, 
           {"lat":21.321238, "lng": 16.8782219, "updated_at": "Mon May 8 2010 11:17:45"}] 
          } 
      ]} 
      

      참고 :

      기본적으로 나는 이런 식으로 뭔가를 달성하고 싶다 그것 가 만들어 질 필요가있다

    • trips.name은 유일해야한다 그래서 존재한다면 ts, 위치 배열에 추가하십시오.

    이것은 위치 연산자를 $ push와 결합하여 작성한 쿼리입니다.

    db.mycollection.update({"application_id": "MyTestApp", 
              "trips.name": "2010-05-10"}, 
              {$push: {'trips.$.loc': {"lat":11, "lng":11} }}, 
              true); 
    

    하지만이 같은 데이터가 발생합니다

    > db.mycollection.find({"application_id":"MyTestApp"})   
    { "_id" : ObjectId("4c29044ebf8544c60506f11f"), 
    "application_id" : "MyTestApp", 
    "trips" : { "$" : { "loc" : [ { "lat" : 11, "lng" : 11 } ] }, 
    "name" : "2010-05-10" } 
    } 
    

    당신은

    • "여행"은 말 그대로 "$"를 가져다가 만든 배열
    • 아니라고 볼 수 있습니다 a 키가 있습니다 (doh!)

    지금까지 MongoDB에 상당히 만족했지만 복잡한 쿼리를 작성하는 데에는 가파른 학습 곡선이 있습니다.

    모든 의견을 환영합니다. 사전에

    감사합니다, 에이미

  • +0

    다시 내 대답은 아래를 확인 - 나는 당신이 매우 가까이해야하는 솔루션 (또는 적어도 뭔가 생각하는 것을 포함하도록 편집) – nearlymonolith

    +0

    이 [SO 스레드] (http://stackoverflow.com/questions/17994552/mongodb-update-documents-in-an-array/17995495#17995495)를 참조하십시오. 이와 비슷한 내용입니다. – user10

    답변

    4

    당신이 할 수있는 위치 연산자 ("$")와 업서 트를 섞지 마십시오. "$"는 삽입 중에 필드 이름으로 취급됩니다. 새 문서에 대해서는이 작업을 수행 할 수 없으며 기존 문서에 대해서는 수행 할 수 없습니다.

    나는 더 이런 구조를 제안 :

    {"_id" : ObjectId("4c28f62cbf8544c60506f11d"), 
    "some_other_data":"goes here", 
    "trips": { 
        "2010-05-10": 
         [{"lat":21.321231, "lng": 16.8783234, "updated_at": "Mon May 10 2010 15:24:35"}, 
         {"lat":21.321231, "lng": 16.8783234, "updated_at": "Mon May 10 2010 15:24:24"}], 
        "2010-05-08": 
         [{"lat":21.324239, "lng": 16.8735234, "updated_at": "Mon May 8 2010 11:18:05"}, 
         {"lat":21.311234, "lng": 16.8743271, "updated_at": "Mon May 8 2010 11:17:55"}, 
         {"lat":21.321238, "lng": 16.8782219, "updated_at": "Mon May 8 2010 11:17:45"}] 
        } 
    } 
    

    는 그런 다음 갱신과 같이 실행할 수 있습니다

    db.mycollection.update({application_id: "MyTestApp", "trips.2010-05-10":{$exists:true}}, 
             {$push: {"trips.2010-05-10": {lat:11, lng:11} }}, 
             true); 
    

    결과를이 삽입에.

    > db.mycollection.find() 
    { "_id" : ObjectId("4c2931d17b210000000045f0"), 
        "application_id" : "MyTestApp", 
        "trips" : { "2010-05-10" : [ { "lat" : 11, "lng" : 11 } ] } } 
    

    와 당신에게 다시 실행이 :

    > db.mycollection.find() 
    { "_id" : ObjectId("4c2932db7b210000000045f2"), 
        "application_id" : "MyTestApp", 
        "trips" : { "2010-05-10" : 
         [ { "lat" : 11, "lng" : 11 }, 
          { "lat" : 11, "lng" : 11 } ] } } 
    
    +0

    이것은 내가 성취하려는 것에 매우 가깝습니다. 고마워요 @ 스캇 헤르 난 데스. 이 스키마를 사용하면 "여행"에서 키 목록을 검색 할 수 있습니까? ("2010-050-10"등) db.mycollection.find ({ "application_id": "MytestApp"}, { "trips": true})는 전체 "trips"해시를 반환합니다. – Grnbeagle

    +0

    나는이 방법으로 끝났다. 솔루션 스콧 주셔서 감사합니다! – Grnbeagle

    +0

    위도 21.321231의 여행 문서를 찾을 때처럼 여행 내에서 무언가를 쿼리 할 수 ​​없다는 문제가 있습니다. (몽고 (오늘)는 필드 경로의 '와일드 카드'부분이 없습니다). – Nick

    1

    이 정확히 내가 몽고 학습 히트 문제입니다 올바른 솔루션

    을 포함하도록 수정 됨 - 당신이 함께 사용되는 $addToSet 연산자 (see docs here) 그건 찾고 update 명령과 함께 사용중인 위치 연산자 $과 함께 사용하십시오.

    $ addToSet

    {$ addToSet : {필드 : 값}} 경우에만이 아니 배열에 이미 배열에

    을 추가 값입니다.

    따라서 쿼리는 (db.스택 내가) 테스트 목적으로 사용되는 모음입니다, 샘플 실행은 다음과 같이하십시오

    db.stack.update({ "trips.name":"2010-05-10" }, 
           { $addToSet: { "trips.$.loc":{"lat":11, "lng":12} } } 
           ); 
    

    테스트 실행 (일부 약어와 중요하지 않은 요소)의 공간 :

    #### YOUR ITEM IN THE DB 
    > db.stack.find({"trips.name":"2010-05-10"}) 
    { "_id" : ObjectId("4c28f62cbf8544c60506f11d"), "some_other_data" : "goes here", 
        "trips" : [ 
        { "name" : "2010-05-10", 
         "loc" : [ { 
           "lat" : 21.321231, 
           "lng" : 16.8783234, 
           "updated_at" : "Mon May 10 2010 15:24:35" 
          }, { "lat" : 21.321231, 
           "lng" : 16.8783234, 
           "updated_at" : "Mon May 10 2010 15:24:24" 
          } ] }, 
        { "name" : "2010-05-08", 
         "loc" : [ ... ] 
        } ] } 
    #### SUCCESSFULLY ADDS ITEM TO PROPER ARRAY 
    > db.stack.update({"trips.name":"2010-05-10"}, {$addToSet: {"trips.$.loc":{"lat":11, "lng":11}}}); 
    > db.stack.findOne() 
    { "_id" : ObjectId("4c28f62cbf8544c60506f11d"), "some_other_data" : "goes here", 
        "trips" : [ 
         { "loc" : [ 
           { "lat" : 21.321231, 
            "lng" : 16.8783234, 
            "updated_at" : "Mon May 10 2010 15:24:35" 
           }, { "lat" : 21.321231, 
            "lng" : 16.8783234, 
            "updated_at" : "Mon May 10 2010 15:24:24" 
           }, { "lat" : 11, 
            "lng" : 11 
           } 
          ], "name" : "2010-05-10" 
         }, 
         { "name" : "2010-05-08", 
          "loc" : [ ... ] 
         } ] } 
    #### ON REPEAT RUN DOESN'T ADD NEW ELEMENT 
    > db.stack.update({"trips.name":"2010-05-10"}, {$addToSet: {"trips.$.loc":{"lat":11, "lng":11}}}); 
    > db.stack.findOne() 
    { "_id" : ObjectId("4c28f62cbf8544c60506f11d"), "some_other_data" : "goes here", 
        "trips" : [ { 
          "loc" : [ 
           { "lat" : 21.321231, 
            "lng" : 16.8783234, 
            "updated_at" : "Mon May 10 2010 15:24:35" 
           }, { "lat" : 21.321231, 
            "lng" : 16.8783234, 
            "updated_at" : "Mon May 10 2010 15:24:24" 
           }, { "lat" : 11, 
            "lng" : 11 
           } 
          ], "name" : "2010-05-10" 
         }, 
         { "name" : "2010-05-08", 
          "loc" : [ ... ] 
         } ] } 
    #### BUT WILL CORRECTLY ADD ANOTHER ELEMENT TO THE SAME ARRAY IF IT'S NOT PRESENT 
    > db.stack.update({"trips.name":"2010-05-10"}, {$addToSet: {"trips.$.loc":{"lat":11, "lng":12}}}); 
    > db.stack.findOne() 
    { "_id" : ObjectId("4c28f62cbf8544c60506f11d"), "some_other_data" : "goes here", 
        "trips" : [ 
         { "loc" : [ 
           { "lat" : 21.321231, 
            "lng" : 16.8783234, 
            "updated_at" : "Mon May 10 2010 15:24:35" 
           }, { "lat" : 21.321231, 
            "lng" : 16.8783234, 
            "updated_at" : "Mon May 10 2010 15:24:24" 
           }, { "lat" : 11, 
            "lng" : 11 
           }, { "lat" : 11, 
            "lng" : 12 
           } 
          ], "name" : "2010-05-10" 
         }, 
         { "name" : "2010-05-08", 
          "loc" : [ ... ] 
        } ] } 
    
    +0

    @Anthony Morelli 응답에 감사드립니다. 나는 $ addToSet을 시도하고 처음으로 여행을 삽입하기 위해 upsert = true를 전달해야했습니다. 여행 이름을 다른 것으로 변경하면 현재 문서를 사용하는 대신 실제로 새 문서가 만들어집니다. "여행"이 배열임을 어떻게 지정할 수 있습니까? – Grnbeagle

    +0

    구체적으로 어떤 쿼리를 실행 했습니까? $ addToSet은 배열에서만 작동하므로 사양이 문제라고 생각하지 않습니다. – nearlymonolith

    +0

    쿼리를 정확히 실행했지만 문서를 만들지 않았으므로 upsert = true를 전달했습니다. 첫 번째 문서를 만든 후 두 번째 문서를 실행하면 두 번째 문서가 이전 문서에 추가되는 대신 두 번째 문서가 만들어졌습니다. – Grnbeagle