mongoDb에서 인덱스로 배열 요소를 제거하는 방법은 무엇입니까?


97

다음 예에서는 문서가 db.people 컬렉션 에 있다고 가정합니다 .

인덱스로 관심사 배열 의 세 번째 요소를 제거하는 방법은 무엇입니까?

{
  "_id" : ObjectId("4d1cb5de451600000000497a"),           
  "name" : "dannie",  
  "interests" : [  
    "guitar",  
    "programming",           
    "gadgets",  
    "reading"  
  ]   
}

이것이 내 현재 솔루션입니다.

var interests = db.people.findOne({"name":"dannie"}).interests;  
interests.splice(2,1)  
db.people.update({"name":"dannie"}, {"$set" : {"interests" : interests}});

더 직접적인 방법이 있습니까?


답변:


138

배열 인덱스로 당기거나 제거하는 직접적인 방법은 없습니다. 실제로 이것은 공개 된 문제입니다 http://jira.mongodb.org/browse/SERVER-1014 , 투표 할 수 있습니다.

해결 방법은 $ unset을 사용한 다음 $ pull을 사용하는 것입니다.

db.lists.update({}, {$unset : {"interests.3" : 1 }}) 
db.lists.update({}, {$pull : {"interests" : null}})

업데이트 : 일부 주석에서 언급했듯이이 접근 방식은 원자 적이 지 않으며 다른 클라이언트가 두 작업 사이에 읽기 및 / 또는 쓰기를 수행하는 경우 일부 경쟁 조건이 발생할 수 있습니다. 작업이 원자 적이어야하는 경우 다음을 수행 할 수 있습니다.

  • 데이터베이스에서 문서 읽기
  • 문서를 업데이트하고 배열에서 항목 제거
  • 데이터베이스의 문서를 바꿉니다. 문서를 읽은 후 변경되지 않았는지 확인하기 위해 현재 패턴 이 mongo 문서에 설명 경우 업데이트를 사용할 수 있습니다.

33
1 년 반 됐어? 이것이 여전히 mongodb의 상태입니까?
Abe

다음 답변은 더 직접적이고 나를 위해 일했습니다. 인덱스로 제거하는 것이 아니라 값으로 제거하는 것입니다.
vish

1
@Javier-인덱스에서 위치를 세는 시간과 설정을 해제 한 시간 사이에 db가 변경되면이 솔루션으로 인해 문제가 발생하지 않습니까?
UpTheCreek 2013-06-25

이것은 원자 적이 지 않으므로 배열의 null 항목에 대처할 준비가되지 않은 코드가있는 경우 모호한 경쟁 조건이 발생할 수 있습니다.
Glenn Maynard

3
8 년 지났지
만이

19

오퍼레이션 $pull수정자를 사용 update하여 배열에서 특정 요소를 제거 할 수 있습니다 . 제공 한 경우 쿼리는 다음과 같습니다.

db.people.update({"name":"dannie"}, {'$pull': {"interests": "guitar"}})

또한 $pullAll모든 발생을 제거하기 위해 를 사용할 수도 있습니다 . 이에 대한 자세한 내용은 공식 문서 페이지-http: //www.mongodb.org/display/DOCS/Updating#Updating-%24pull

이것은 요소를 제거하기위한 기준으로 색인을 사용하지 않지만 유사한 경우에 도움이 될 수 있습니다. IMO, 배열 내부의 요소 주소 지정을 위해 인덱스를 사용하는 것은 mongodb가 내가 아는 것처럼 요소 순서에서 일관성이 없기 때문에 매우 신뢰할 수 없습니다.


6
그의 요소는 질문의 배열입니다. 이 경우 Mongo는 순서대로 일관성이 있습니다. 실제로 모든 문서는 실제로 주문 된 컬렉션이지만 많은 드라이버가 이러한 방식으로 문서를 처리하지 않습니다. 더 복잡한 문제는 업데이트 작업 후 문서를 이동해야하는 경우 (패딩 요소를 넘어서 증가하기 때문에) 키의 순서가 갑자기 알파벳순이됩니다. (내 생각에는 이진 값으로 정렬되어 있다고 생각합니다.이 의심은 배열이 문자열 대신 연속적인 정수인 키가있는 거의 표준 문서라는 내 지식을 기반으로합니다.
marr75

이렇게하면 unset + pull 문제를 피할 수 있지만 사전을 엄격하게 정렬해야합니다. 대부분의 언어로 된 사전은 순서가 지정되어 있지 않기 때문에 이런 일이 발생하는 것이 어려울 수 있습니다.
Glenn Maynard 2013

@ marr75 : 참고 문헌이 있습니까? Mongo 문서는 항상 순서를 유지해야하며 하위 문서의 순서를 변경하면 많은 일이 깨질 것입니다.
Glenn Maynard

참조가 없습니다. 2.2에 대한 개인적인 경험을 통해이 사실을 알고 있으며 업데이트 및 이동 된 문서에 의해 도입 된 버그를 수정했습니다. 지난 몇 달 동안 몽고 작업을 많이하지 않았기 때문에 최신 버전에 대해 이야기 할 수 없습니다.
marr75

요소 일관성에 관해서는 내가 원하는 사용 사례입니다. 클라이언트는 mongo에서 json을 요청한 다음 클라이언트가 json 배열에서 항목을 '삭제'하기로 선택하면 삭제할 서버에 배열 인덱스를 전달합니다. 배열 항목의 위치가 이동 한 경우, 그 이상한 것,하지만이 기능을 구현하지 못할 이유를 설명하는 것
meffect

4

설정되지 않은 답변을 사용하는 대신 필드를 고유 한 값 (즉, NULL이 아님)으로 설정 한 다음 즉시 해당 값을 가져 와서이 문제를 해결합니다. 비동기 관점에서 조금 더 안전합니다. 다음은 코드입니다.

    var update = {};
    var key = "ToBePulled_"+ new Date().toString();
    update['feedback.'+index] = key;
    Venues.update(venueId, {$set: update});
    return Venues.update(venueId, {$pull: {feedback: key}});

mongo가 $ position 수정자를 $ push와 $ pull을 지원하도록 확장하여이 문제를 해결하기를 바랍니다.


3

GUID (ObjectID를 사용하는 경향이 있음) 필드 또는 배열의 각 하위 문서에 대해 자동 증가 필드를 사용하는 것이 좋습니다.

이 GUID를 사용하면 $ pull을 쉽게 실행할 수 있으며 올바른 GUID를 가져올 수 있습니다. 다른 어레이 작업도 마찬가지입니다.


2

의 시작 Mongo 4.4$function집계 연산자는 MongoDB의 쿼리 언어가 지원하지 않는 동작을 구현하기 위해 사용자 지정 자바 스크립트 함수를 적용 허용한다.

예를 들어, 주어진 인덱스에서 요소를 제거하여 배열을 업데이트하려면 :

// { "name": "dannie", "interests": ["guitar", "programming", "gadgets", "reading"] }
db.collection.update(
  { "name": "dannie" },
  [{ $set:
    { "interests":
      { $function: {
          body: function(interests) { interests.splice(2, 1); return interests; },
          args: ["$interests"],
          lang: "js"
      }}
    }
  }]
)
// { "name": "dannie", "interests": ["guitar", "programming", "reading"] }

$function 3 개의 매개 변수를 사용합니다.

  • body, 적용 할 함수이며 매개 변수는 수정할 배열입니다. 여기서 기능은 단순히 스플 라이스를 사용하여 인덱스 2에서 1 개의 요소를 제거하는 것으로 구성됩니다.
  • args, body함수가 매개 변수로 사용 하는 레코드의 필드를 포함합니다 . 우리의 경우 "$interests".
  • lang, body함수가 작성 되는 언어 입니다. js현재 만 사용할 수 있습니다.

2

Mongodb 4.2에서는 다음을 수행 할 수 있습니다.

db.example.update({}, [
     {$set: {field: {
           $concatArrays: [ 
                  {$slice: ["$field", P]}, 
                  {$slice: ["$field", {$add: [1, P]}, {$size: "$field"}]}
           ]
     }}}
]);

P는 배열에서 제거하려는 요소의 인덱스입니다.

끝까지 P에서 제거하려면 :

db.example.update({}, [
     {$set: {field: {$slice: ["$field", P]}}
]);

0

nodejs와 함께 mongoose를 사용하여 답변을 검색하는 사람들을 위해. 이것이 내가하는 방법이다.

exports.deletePregunta = function (req, res) {
let codTest = req.params.tCodigo;
let indexPregunta = req.body.pregunta; // the index that come from frontend
let inPregunta = `tPreguntas.0.pregunta.${indexPregunta}`; // my field in my db
let inOpciones = `tPreguntas.0.opciones.${indexPregunta}`; // my other field in my db
let inTipo = `tPreguntas.0.tipo.${indexPregunta}`; // my  other field in my db

Test.findOneAndUpdate({ tCodigo: codTest },
    {
        '$unset': {
            [inPregunta]: 1, // put the field with [] 
            [inOpciones]: 1,
            [inTipo]: 1
        }
    }).then(()=>{ 
    Test.findOneAndUpdate({ tCodigo: codTest }, {
        '$pull': {
            'tPreguntas.0.pregunta': null,
            'tPreguntas.0.opciones': null,
            'tPreguntas.0.tipo': null
        }
    }).then(testModificado => {
        if (!testModificado) {
            res.status(404).send({ accion: 'deletePregunta', message: 'No se ha podido borrar esa pregunta ' });
        } else {
            res.status(200).send({ accion: 'deletePregunta', message: 'Pregunta borrada correctamente' });
        }
    })}).catch(err => { res.status(500).send({ accion: 'deletePregunta', message: 'error en la base de datos ' + err }); });
 }

이 답변이 잘 이해되지 않으면 다시 쓸 수 있지만 괜찮다고 생각합니다.

이것이 도움이되기를 바랍니다.이 문제에 직면하여 많은 시간을 잃었습니다.


-3

$ pull을 사용하는 대신 인덱스로 배열의 요소를 제거하기 위해 $ pop을 사용할 수 있습니다. 그러나 인덱스를 기준으로 제거하려면 인덱스 위치에서 1을 빼야합니다.

예를 들어 인덱스 0의 요소를 제거하려면 -1을 사용해야하고, 인덱스 1에는 0을 사용해야합니다.

세 번째 요소 (가젯)를 제거하기위한 쿼리 :

db.people.update({"name":"dannie"}, {'$pop': {"interests": 1}})

참고로 : https://docs.mongodb.com/manual/reference/operator/update/pop/


4
링크 된 문서에 따르면 $pop배열에서 첫 번째 또는 마지막 요소 만 제거 할 수 있습니다. 이 답변의 쿼리는 세 번째 요소를 제거하지 않습니다.
Travis G.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.