programing

키 이름의 MongoDB 도트(.)

abcjava 2023. 3. 2. 21:52
반응형

키 이름의 MongoDB 도트(.)

mongo에서는 도트(.)나 달러 기호($)가 있는 키를 삽입할 수 없는 것 같습니다만, mongo Import 툴을 사용하여 도트가 들어간 JSON 파일을 Import 했을 때는 정상적으로 동작했습니다.드라이버가 그 요소를 삽입하려고 한다고 불평하고 있습니다.

데이터베이스의 문서는 다음과 같습니다.

{
    "_id": {
        "$oid": "..."
    },
    "make": "saab",
    "models": {
        "9.7x": [
            2007,
            2008,
            2009,
            2010
        ]
    }
}

이 모든 것이 잘못되어 외부 데이터(모델 등)에 해시 맵을 사용하면 안 되는 건가요?아니면 어떻게든 점을 벗어날 수 있을까요?자바스크립트 같은 생각을 너무 많이 했나 봐요.

MongoDB는 도트가 있는 키를 지원하지 않기 때문에 가져오기 전에 JSON 파일을 제거/교체하기 위해 사전 처리를 해야 합니다.그렇지 않으면 모든 종류의 문제에 대처할 수 있습니다.

이 문제에 대한 표준적인 회피책은 없습니다.최선의 접근법은 상황의 세부 사항에 따라 너무 다릅니다.그러나 JSON 재구축은 아마도 일회성 비용이 될 수 있기 때문에 가능한 한 주요 인코더/디코더 접근방식은 피하고 싶습니다.

와 같이 는 MongoDB를 하지 않습니다.$ ★★★★★★★★★★★★★★★★★」. 필드 이름의 제한으로 인해 문자가 맵 키로 지정됩니다.그러나 "Dollar Sign Operator Escape"에서 언급한 바와 같이, 이러한 키로 문서를 삽입할 수 없도록 하는 것은 아니며, 문서를 업데이트하거나 쿼리할 수 없도록 할 입니다.

「」를 치환하는 .[dot] ★★★★★★★★★★★★★★★★★」U+FF0E되어 있는 와 같이) 를 저장하려고 할 때 [dot] ★★★★★★★★★★★★★★★★★」U+FF0E

Fantom의 afMorphia 드라이버가 취하는 접근법은 Java와 유사한 Unicode 이스케이프 시퀀스를 사용하되 이스케이프 문자를 먼저 이스케이프하는 것입니다.기본적으로 다음과 같은 문자열 치환이 이루어집니다(*).

\  -->  \\
$  -->  \u0024
.  -->  \u002e

이후 MongoDB에서 맵 키를 읽을 때 역치환이 이루어집니다.

또는 Fantom 코드:

Str encodeKey(Str key) {
    return key.replace("\\", "\\\\").replace("\$", "\\u0024").replace(".", "\\u002e")
}

Str decodeKey(Str key) {
    return key.replace("\\u002e", ".").replace("\\u0024", "\$").replace("\\\\", "\\")
}

사용자가 이러한 변환을 인식할 필요가 있는 것은 이러한 키에 대한 쿼리를 구성할 때뿐입니다.

일반적으로 은 given given given given given given given given given given given given given given given given given 。dotted.property.names이러한 맵 키를 단순히 금지하는 것보다 이 접근법이 더 바람직하다고 생각합니다.

(*) afMorphia는 실제로 Java의 Unicode 이스케이프 구문에 기재되어 있는 완전하고 적절한 Unicode 이스케이프 규칙을 실행하지만, 기재되어 있는 치환 시퀀스는 그대로 기능합니다.

MongoDB의 최신 안정 버전(v3.6.1)은 현재 키 또는 필드 이름에 점(.)을 지원합니다.

필드 이름에는 점(.)과 달러($) 문자를 사용할 수 있습니다.

Mongo 문서는 다음과 같은 불법 문자를 대체할 것을 제안합니다.$ ★★★★★★★★★★★★★★★★★」.이치노

이러한 상황에서는 예약된 $ 및 . 문자를 키로 대체해야 합니다.어떤 문자라도 상관없습니다만, Unicode 전폭에 대응하는 문자를 사용하는 것을 검토해 주세요.U+FF04(즉, "")")와 U+FF0E(즉, "")입니다.

제가 방금 구현한 솔루션은 키 이름과 값을 두 개의 다른 필드로 나누는 것입니다.이렇게 하면 캐릭터를 그대로 유지할 수 있고 악몽을 해석하는 것에 대해 걱정할 필요가 없습니다.문서는 다음과 같습니다.

{
    ...
    keyName: "domain.com",
    keyValue: "unregistered",
    ...
}

할 수 find [ keyName and keyValue ]필드에 표시됩니다.

그래서 다음 대신:

 db.collection.find({"domain.com":"unregistered"})

실제로 예상대로 작동하지 않을 경우 다음과 같이 실행됩니다.

db.collection.find({keyName:"domain.com", keyValue:"unregistered"})

그러면 예상한 서류가 반환됩니다.

키에서 값 대신 해시를 사용하여 해당 값을 JSON 값에 저장할 수 있습니다.

var crypto = require("crypto");   

function md5(value) {
    return crypto.createHash('md5').update( String(value) ).digest('hex');
}

var data = {
    "_id": {
        "$oid": "..."
    },
    "make": "saab",
    "models": {}
}

var version = "9.7x";

data.models[ md5(version) ] = {
    "version": version,
    "years" : [
        2007,
        2008,
        2009,
        2010
    ]
}

그런 다음 나중에 해시를 사용하여 모델에 액세스합니다.

var version = "9.7x";
collection.find( { _id : ...}, function(e, data ) {
    var models = data.models[ md5(version) ];
}

현재 지원되고 있습니다.

MongoDb 3.6 이후에는 필드 이름에서 도트와 달러를 모두 지원합니다.아래 JIRA 참조:https://jira.mongodb.org/browse/JAVA-2810

Mongodb를 3.6 이상으로 업그레이드하는 것이 가장 좋은 방법입니다.

열쇠를 피해야 할 거야.대부분의 사람들이 제대로 줄을 피하는 방법을 모르는 것 같기 때문에, 다음과 같은 단계를 거칩니다.

  1. 이스케이프 문자를 선택합니다(거의 사용하지 않는 문자를 선택하는 것이 좋습니다).예: '~'
  2. 이스케이프하려면 먼저 이스케이프 문자의 모든 인스턴스를 이스케이프 문자 앞에 있는 시퀀스(예: '~' -> '~t')로 바꾼 다음 이스케이프 문자 앞에 있는 시퀀스 또는 이스케이프 문자를 바꿉니다.예. -> '~p'
  3. 이스케이프를 해제하려면 먼저 두 번째 이스케이프 시퀀스의 모든 인스턴스(예: '~p' -> '.)에서 이스케이프 시퀀스를 제거한 후 이스케이프 문자 시퀀스를 단일 이스케이프 문자(예: '~s' -> '~')로 변환합니다.

또한 mongo는 키가 $로 시작하는 것을 허용하지 않기 때문에 거기서 유사한 작업을 수행해야 합니다.

이 기능을 하는 코드는 다음과 같습니다.

// returns an escaped mongo key
exports.escape = function(key) {
  return key.replace(/~/g, '~s')
            .replace(/\./g, '~p')
            .replace(/^\$/g, '~d')
}

// returns an unescaped mongo key
exports.unescape = function(escapedKey) {
  return escapedKey.replace(/^~d/g, '$')
                   .replace(/~p/g, '.')
                   .replace(/~s/g, '~')
}

MongoDB 문서에서 ".'. 문자는 키 이름 어디에도 표시되지 않아야 합니다."부호화 방식을 생각해내든지 아니면 없애든지 해야 할 것 같아요.

이지만, 몽고를 은 봄과 몽고에서 을 관리할 수 .MappingMongoConverter홍콩 봄

@Autowired
private MappingMongoConverter converter;

@PostConstruct
public void configureMongo() {
 converter.setMapKeyDotReplacement("xxx");
}

저장된 Json의 경우:

{ "axxxb" : "value" }

봄(MongoClient)에서는 다음과 같이 읽힙니다.

{ "a.b" : "value" }

또 다른 사용자가 언급했듯이, 나중에 부호화/복호화가 문제가 될 수 있으므로 점이 있는 모든 키를 교체하는 것이 더 쉬울 수 있습니다.다음은 키를 '.'로 바꾸기 위해 만든 재귀 함수입니다.

def mongo_jsonify(dictionary):
    new_dict = {}
    if type(dictionary) is dict:
        for k, v in dictionary.items():
            new_k = k.replace('.', '-')
            if type(v) is dict:
                new_dict[new_k] = mongo_jsonify(v)
            elif type(v) is list:
                new_dict[new_k] = [mongo_jsonify(i) for i in v]
            else:
                new_dict[new_k] = dictionary[k]
        return new_dict
    else:
        return dictionary

if __name__ == '__main__':
    with open('path_to_json', "r") as input_file:
        d = json.load(input_file)
    d = mongo_jsonify(d)
    pprint(d)

이 코드를 수정하여 '$'를 대체할 수도 있습니다. 이는 mongo에서 키를 사용할 수 없는 또 다른 문자이기 때문입니다.

각 오브젝트 키에 대해 JavaScript에서 다음 이스케이프를 사용합니다.

key.replace(/\\/g, '\\\\').replace(/^\$/, '\\$').replace(/\./g, '\\_')

'만'을 대신한다는 것이다.$콘솔에서 사용하기 어려운 유니코드 문자를 사용하지 않습니다. _ 특수문자 : 1개, 1개)를 대체하는 .$,.)른하지만 전통적인 방식으로는 적절히 탈출할 수 있습니다.\.

완벽하지는 않지만 대부분의 상황에서 사용할 수 있습니다. 금지된 문자를 다른 문자로 대체하십시오.키 안에 있기 때문에, 이 새로운 글자는 꽤 드물 것입니다.

/** This will replace \ with ⍀, ^$ with '₴' and dots with ⋅  to make the object compatible for mongoDB insert. 
Caveats:
    1. If you have any of ⍀, ₴ or ⋅ in your original documents, they will be converted to \$.upon decoding. 
    2. Recursive structures are always an issue. A cheap way to prevent a stack overflow is by limiting the number of levels. The default max level is 10.
 */
encodeMongoObj = function(o, level = 10) {
    var build = {}, key, newKey, value
    //if (typeof level === "undefined") level = 20     // default level if not provided
    for (key in o) {
        value = o[key]
        if (typeof value === "object") value = (level > 0) ? encodeMongoObj(value, level - 1) : null     // If this is an object, recurse if we can

        newKey = key.replace(/\\/g, '⍀').replace(/^\$/, '₴').replace(/\./g, '⋅')    // replace special chars prohibited in mongo keys
        build[newKey] = value
    }
    return build
}

/** This will decode an object encoded with the above function. We assume the structure is not recursive since it should come from Mongodb */
decodeMongoObj = function(o) {
    var build = {}, key, newKey, value
    for (key in o) {
        value = o[key]
        if (typeof value === "object") value = decodeMongoObj(value)     // If this is an object, recurse
        newKey = key.replace(/⍀/g, '\\').replace(/^₴/, '$').replace(/⋅/g, '.')    // replace special chars prohibited in mongo keys
        build[newKey] = value
    }
    return build
}

다음은 테스트입니다.

var nastyObj = {
    "sub.obj" : {"$dollar\\backslash": "$\\.end$"}
}
nastyObj["$you.must.be.kidding"] = nastyObj     // make it recursive

var encoded = encodeMongoObj(nastyObj, 1)
console.log(encoded)
console.log( decodeMongoObj( encoded) )

및 결과 - 값은 변경되지 않습니다.

{
  sub⋅obj: {
    ₴dollar⍀backslash: "$\\.end$"
  },
  ₴you⋅must⋅be⋅kidding: {
    sub⋅obj: null,
    ₴you⋅must⋅be⋅kidding: null
  }
}
[12:02:47.691] {
  "sub.obj": {
    $dollar\\backslash: "$\\.end$"
  },
  "$you.must.be.kidding": {
    "sub.obj": {},
    "$you.must.be.kidding": {}
  }
}

디버깅 목적이 아닌 응용 프로그램에서 사용하지 않는 것을 쿼리하는 추악한 방법이 있습니다(매립형 객체에서만 작동).

db.getCollection('mycollection').aggregate([
    {$match: {mymapfield: {$type: "object" }}}, //filter objects with right field type
    {$project: {mymapfield: { $objectToArray: "$mymapfield" }}}, //"unwind" map to array of {k: key, v: value} objects
    {$match: {mymapfield: {k: "my.key.with.dot", v: "myvalue"}}} //query
])

PHP HTML을 사용합니다.그그입니다.".".

다음과 같이 MongoDB에 저장됩니다.

  "validations" : {
     "4e25adbb1b0a55400e030000" : {
     "associate" : "true" 
    },
     "4e25adb11b0a55400e010000" : {
       "associate" : "true" 
     } 
   } 

PHP 코드...

  $entry = array('associate' => $associate);         
  $data = array( '$set' => array( 'validations.' . str_replace(".", `"."`, $validation) => $entry ));     
  $newstatus = $collection->update($key, $data, $options);      

Lodash 쌍으로 변경할 수 있습니다.

{ 'connect.sid': 's:hyeIzKRdD9aucCc5NceYw5zhHN5vpFOp.0OUaA6' }

안으로

[ [ 'connect.sid',
's:hyeIzKRdD9aucCc5NceYw5zhHN5vpFOp.0OUaA6' ] ]

사용.

var newObj = _.pairs(oldObj);

그대로 보관하고 나중에 예쁘게 변환할 수 있습니다.

나는 이 예를 Livescript에 썼다.livescript.net 웹사이트를 사용하여 평가할 수 있습니다.

test =
  field:
    field1: 1
    field2: 2
    field3: 5
    nested:
      more: 1
      moresdafasdf: 23423
  field3: 3



get-plain = (json, parent)->
  | typeof! json is \Object => json |> obj-to-pairs |> map -> get-plain it.1, [parent,it.0].filter(-> it?).join(\.)
  | _ => key: parent, value: json

test |> get-plain |> flatten |> map (-> [it.key, it.value]) |> pairs-to-obj

생산될 것이다

{"field.field1":1,
 "field.field2":2,
 "field.field3":5,
 "field.nested.more":1,
 "field.nested.moresdafasdf":23423,
 "field3":3}

힌트를 드리겠습니다.JSON.stringify를 사용하여 객체/어레이에 도트가 있는 키 이름을 저장하고 데이터베이스에서 데이터를 가져올 때 처리할 문자열을 JSON.parse를 사용하여 객체에 해석할 수 있습니다.

또 다른 회피책:스키마를 다음과 같이 재구성합니다.

key : {
"keyName": "a.b"
"value": [Array]
}

최신 MongoDB는 도트가 있는 키를 지원하지만 Java MongoDB 드라이버는 지원하지 않습니다.그래서 자바에서 동작시키기 위해 java-mongo-driver의 github repo에서 코드를 추출하고 그에 따라 isValid Key 기능을 변경하여 새로운 jar를 만들어 지금 사용하고 있습니다.

도트를 바꿉니다(.) 또는 달러($( )는, 실제의 문서에서는 사용되지 않는 다른 문자입니다.그리고 점을 복원한다..) 또는 달러($)을 클릭합니다.이 전략은 사용자가 읽는 데이터에 영향을 주지 않습니다.

모든 문자에서 문자를 선택할 수 있습니다.

이상한 점은 mongoj를 사용하여 직접 _id를 설정하면 점으로 된 문서를 만들 수 있지만 _id가 생성되면 문서를 만들 수 없다는 것입니다.

동작:

db.testcollection.save({"_id": "testdocument", "dot.ted.": "value"}, (err, res) => {
    console.log(err, res);
});

동작하지 않음:

db.testcollection.save({"dot.ted": "value"}, (err, res) => {
    console.log(err, res);
});

처음에는 도트키로 문서를 갱신하는 것도 효과가 있다고 생각했는데, 도트를 서브키라고 하는 것이군요!

mongojs가 도트(서브키)를 처리하는 것을 보고 내 키에 도트가 없는지 확인합니다.

예를 들면 @JohnnyHK에서는 데이터가 더 큰 데이터 세트로 축적되기 시작하면 더 큰 문제가 발생하므로 키에서 구두점이나 '.'을 삭제해야 한다고 언급했습니다.이는 특히 $merge와 같은 집약 연산자를 호출할 때 문제를 일으키며, 이 경우 키에 액세스하여 비교해야 오류가 발생합니다.어렵게 배웠어요.처음 하시는 분들은 반복하지 말아주세요.

이 경우 마침표가 있는 속성은 사용자가 직접 쿼리하지 않습니다.그러나 사용자가 생성할 수 있습니다.

따라서 먼저 전체 모델을 직렬화하고 문자열이 특정 필드의 모든 인스턴스를 대체합니다.기간 필드는 여러 위치에 표시될 수 있으며 데이터의 구조를 예측할 수 없습니다.

    var dataJson = serialize(dataObj);
    foreach(pf in periodFields) 
    {  
         var encodedPF = pf.replace(".", "ENCODE_DOT");
         dataJson.replace(pf, encodedPF);
    }

그리고 나중에 데이터가 평탄화된 후 인코딩된 인스턴스를 교체합니다.디코딩된 버전을 파일에 쓸 수 있도록 PF를 사용합니다.

아무도 ENCODE_DOT라는 필드를 필요로 하지 않기 때문에 이 경우 문제가 되지 않습니다.

결과는 다음과 같습니다.하나는 colorENCODE_DOTONE으로 데이터베이스에 저장됩니다.

파일을 쓸 때는 ENCODE_DOT를 로 바꿉니다.

/home/user/anaconda3/lib/python3.6/site-packages/pymongo/collection.py

에러 메세지에 기재되어 있습니다.「 」를 사용하고 anaconda 수 없는 만 하면 .check_keys = True로로 합니다.False상기의 파일에 기재되어 있습니다.잘될!!

언급URL : https://stackoverflow.com/questions/12397118/mongodb-dot-in-key-name

반응형