programing

동일한 문서의 필드가 있는 Mongodb 쿼리

subpage 2023. 5. 4. 19:57
반응형

동일한 문서의 필드가 있는 Mongodb 쿼리

다음과 같은 json이 있습니다.

{
  "a1": {"a": "b"},
  "a2": {"a": "c"}
}

다음 위치에서 모든 문서를 요청하려면 어떻게 해야 합니까?a1그리고.a2동일한 문서에서 동일하지 않습니까?

다음을 사용할 수 있습니다.

db.myCollection.find( { $where: "this.a1.a != this.a2.a" } )

그러나 자바 스크립트 엔진을 회전시켜 각 문서를 반복하고 각 문서의 상태를 확인해야 하므로 이 작업은 그리 빠르지 않습니다.

이 매우 수행해야 할 에는 모대컬에대수야행하거매나해우자주수하행다는좋니습과 정규화되지 플래그를 이 가장 .areEqual여전히, 그러한 낮은 선택성 필드는 후보 집합이 여전히 크기 때문에 좋은 인덱스 성능을 산출하지 못합니다.

갱신하다

mongo 3.6 현재 사용 가능한 새로운 $expr 연산자를 사용하여 다음과 같은 find 쿼리에서 집계 표현식을 사용할 수 있습니다.

  db.myCollection.find({$expr: {$ne: ["$a1.a", "$a2.a"] } });

의견으로 문제가 해결되었지만, 이 사용 사례와 더 잘 맞는 것은 $project 대신 버전 3.4에서 사용 가능한 $addFields 연산자를 사용하는 것이라고 생각합니다.

db.myCollection.aggregate([
     {"$match":{"a1":{"$exists":true},"a2":{"$exists":true}}},
     {"$addFields": {
           "aEq": {"$eq":["$a1.a","$a2.a"]}
         }
     },
     {"$match":{"aEq": false}} 
  ]);

JavaScript를 방지하려면 집계 프레임워크를 사용합니다.

db.myCollection.aggregate([
  {"$match":{"a1":{"$exists":true},"a2":{"$exists":true}}},
  {"$project": {
      "a1":1,
      "a2":1,
      "aCmp": {"$cmp":["$a1.a","$a2.a"]}
    }
  },
  {"$match":{"aCmp":0}}
])

개발 서버에서 동일한 JavaScript 쿼리를 완료하는 데 7배 더 오래 걸립니다.

업데이트(2017년 5월 10일)

저는 제 대답이 동등하지 않은 가치를 원하는 질문에 대답하지 않았다는 것을 깨달았습니다(때로는 제가 정말 느릴 때도 있습니다).이 작업은 다음과 같습니다.

db.myCollection.aggregate([
  {"$match":{"a1":{"$exists":true},"a2":{"$exists":true}}},
  {"$project": {
      "a1":1,
      "a2":1,
      "aEq": {"$eq":["$a1.a","$a2.a"]}
    }
  },
  {"$match":{"aEq": false}}
])

$ne대신 사용할 수 있습니다.$eq이 기조건로변경우경된으로 true하지만 저는 그것을 사용합니다.$eq와 함께false좀 더 직관적으로.

MongoDB는 백그라운드에서 Javascript를 사용하기 때문에

{"a": "b"} == {"a": "b"}

되요지일 입니다.false.

따라서 각각을 비교하려면 a1.a == a2.a가 필요합니다.

MongoDB에서 이 작업을 수행하려면 $where 연산자를 사용합니다.

db.myCollection.find({$where: "this.a1.a != this.a2.a"});

이것은 내장된 각 문서가 속성 "a"를 갖는다고 가정합니다.그렇지 않으면 일이 더 복잡해집니다.

에서 시작Mongo 4.4원시 값뿐만 아니라 하위 값을 비교하려는 사람들을 위해(이후).{"a": "b"} == {"a": "b"}이라false), 사용자 정의 Javascript 함수를 적용할 수 있는 새로운 집계 연산자를 사용할 수 있습니다.

// { "a1" : { "x" : 1, "y" : 2 }, "a2" : { "x" : 1, "y" : 2 } }
// { "a1" : { "x" : 1, "y" : 2 }, "a2" : { "x" : 3, "y" : 2 } }
db.collection.aggregate(
  { $match:
    { $expr:
      { $function: {
          body: function(a1, a2) { return JSON.stringify(a1) != JSON.stringify(a2); },
          args: ["$a1", "$a2"],
          lang: "js"
      }}
    }
  }
)
// { "a1" : { "x" : 1, "y" : 2 }, "a2" : { "x" : 3, "y" : 2 } }

$function세 가지 매개 변수를 사용합니다.

  • body이는 적용할 함수이며 매개 변수는 비교할 두 필드입니다.
  • args여기에는 레코드의 필드가 포함되어 있습니다.body함수는 매개 변수로 사용됩니다. 에는 둘 다."$a1"그리고."$a2".
  • lang그것이 그 언어입니다.body함수가 작성되었습니다..js현재 사용할 수 있습니다.

aggregate()를 사용하는 답변과 관련하여 처음에 저를 혼란스럽게 했던 한 가지는 $eq(또는 $in 또는 많은 다른 연산자)가 사용되는 위치에 따라 다른 의미를 가지고 있다는 것입니다.find() 또는 $match 집계 단계에서 $eq는 단일 값을 사용하고 일치하는 문서를 선택합니다.

db.items.aggregate([{$match: {_id: {$eq: ObjectId("5be5feb45da16064c88e23d4")}}}])

그러나 $project 집계 단계에서 $eq는 2개의 식을 사용하고 값이 true 또는 false인 새 필드를 만듭니다.

db.items.aggregate([{$project: {new_field: {$eq: ["$_id", "$foreignID"]}}}])

프로젝트에서 사용한 쿼리는 버그로 인해 링크된 항목 목록이 자신과 연결된 모든 항목을 찾는 데 사용되었습니다.

db.items.aggregate([{$project: {idIn: {$in: ["$_id","$header.links"]}, "header.links": 1}}, {$match: {idIn: true}}])

언급URL : https://stackoverflow.com/questions/8433046/mongodb-query-with-fields-in-the-same-documents

반응형