키 이름의 MongoDB 점 (.)
mongo는 점 (.) 또는 달러 기호 ($)가있는 키 삽입을 허용하지 않는 것 같지만 mongoimport 도구를 사용하여 점이 포함 된 JSON 파일을 가져 오면 제대로 작동했습니다. 운전자가 해당 요소를 삽입하려는 것에 대해 불평하고 있습니다.
데이터베이스에서 문서는 다음과 같습니다.
{
"_id": {
"$oid": "..."
},
"make": "saab",
"models": {
"9.7x": [
2007,
2008,
2009,
2010
]
}
}
내가이 모든 일을 잘못하고 있고 외부 데이터 (예 : 모델)와 함께 해시 맵을 사용해서는 안됩니까? 아니면 어떻게 든 점을 이스케이프 할 수 있습니까? 어쩌면 나는 너무 많은 Javascript와 비슷하다고 생각하고 있습니다.
MongoDB는 점이 있는 키를 지원하지 않으므로 가져 오기 전에 JSON 파일을 제거 / 교체하기 위해 사전 처리해야합니다. 그렇지 않으면 모든 종류의 문제에 대해 스스로 설정해야합니다.
이 문제에 대한 표준 해결 방법은 없으며 최상의 방법은 상황의 세부 사항에 너무 의존적입니다. 하지만 가능한 한 모든 주요 인코더 / 디코더 접근 방식을 피하고 싶습니다. JSON 재구성은 아마도 일회성 비용이 될 것입니다.
몽고의 워드 프로세서 와 같은 잘못된 문자를 교체 할 것을 제안 $
하고 .
자신의 유니 코드 등가물.
이러한 상황에서 키는 예약 된 $ 및을 대체해야합니다. 문자. 모든 문자로 충분하지만 U + FF04 (예 : "$") 및 U + FF0E (예 : ".")와 같은 유니 코드 전체 너비를 사용하는 것이 좋습니다.
다른 답변에서 언급했듯이 MongoDB는 필드 이름 에 대한 제한으로 인해 $
또는 .
문자를 맵 키로 허용하지 않습니다 . 그러나 달러 기호 연산자 에서 언급 했듯이이 제한 사항을 이스케이프 한다고해서 이러한 키가있는 문서 를 삽입 할 수있는 것은 아닙니다. 문서를 업데이트하거나 쿼리 할 수 없습니다.
단순히 교체의 문제 .
와 함께 [dot]
나 U+FF0E
(이 페이지에 다른 곳에서 언급 한 바와 같이이) 어떤 사용자가 합법적으로 키 저장하려고 할 때 발생한다 [dot]
또는 U+FF0E
?
Fantom의 afMorphia 드라이버 가 취하는 접근 방식 은 Java와 유사한 유니 코드 이스케이프 시퀀스를 사용하지만 이스케이프 문자가 먼저 이스케이프되도록하는 것입니다. 본질적으로 다음과 같은 문자열 대체가 이루어집니다 (*).
\ --> \\
$ --> \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("\\\\", "\\")
}
사용자가 이러한 변환을 인식해야하는 유일한 시간은 해당 키에 대한 쿼리를 구성 할 때입니다.
dotted.property.names
구성 목적으로 데이터베이스에 저장하는 것이 일반적이라는 점을 감안할 때 이러한 접근 방식이 모든 맵 키를 단순히 금지하는 것보다 낫다고 생각합니다.
(*) afMorphia는 실제로 Java의 유니 코드 이스케이프 구문에 언급 된대로 전체 / 적절한 유니 코드 이스케이프 규칙을 수행 하지만 설명 된 대체 시퀀스도 잘 작동합니다.
방금 구현 한 솔루션 중 정말 만족 스럽습니다. 키 이름과 값을 두 개의 개별 필드로 분할하는 것입니다. 이렇게하면 문자를 똑같이 유지할 수 있으며 구문 분석 악몽에 대해 걱정할 필요가 없습니다. 문서는 다음과 같습니다.
{
...
keyName: "domain.com",
keyValue: "unregistered",
...
}
keyName 및 keyValuefind
필드 에서 a 를 수행하여 쉽게 쿼리 할 수 있습니다 .
그래서 대신 :
db.collection.find({"domain.com":"unregistered"})
실제로 예상대로 작동하지 않을 경우 다음을 실행합니다.
db.collection.find({keyName:"domain.com", keyValue:"unregistered"})
예상 된 문서를 반환합니다.
MongoDB의 최신 안정 버전 (v3.6.1)은 이제 키 또는 필드 이름에 점 (.)을 지원합니다.
이제 필드 이름에 점 (.) 및 달러 ($) 문자가 포함될 수 있습니다.
값 대신 키에 해시를 사용한 다음 해당 값을 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를 워드 프로세서 은 " '.' 문자는 키 이름에 표시되지 않아야합니다. " 인코딩 체계를 생각해 내야하거나없이해야 할 것 같습니다.
열쇠를 탈출해야합니다. 대부분의 사람들은 문자열을 올바르게 이스케이프하는 방법을 모르는 것 같으므로 다음 단계를 따르십시오.
- 이스케이프 문자를 선택하십시오 (거의 사용하지 않는 문자를 선택하는 것이 가장 좋습니다). 예 : '~'
- 이스케이프하려면 먼저 이스케이프 문자의 모든 인스턴스를 이스케이프 문자가 추가 된 시퀀스 (예 : '~'-> '~ t')로 바꾼 다음 이스케이프해야하는 문자 나 시퀀스를 이스케이프 문자가 추가 된 시퀀스로 바꿉니다. . 예 : '.' -> '~ p'
- 이스케이프를 해제하려면 먼저 두 번째 이스케이프 시퀀스 (예 : '~ 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, '~')
}
늦은 답변이지만 Spring과 Mongo를 사용하는 경우 Spring은 MappingMongoConverter
. JohnnyHK의 솔루션이지만 Spring에서 처리합니다.
@Autowired
private MappingMongoConverter converter;
@PostConstruct
public void configureMongo() {
converter.setMapKeyDotReplacement("xxx");
}
저장된 Json이 다음과 같은 경우 :
{ "axxxb" : "value" }
Spring (MongoClient)을 통해 다음과 같이 읽 힙니다.
{ "a.b" : "value" }
지금 지원됩니다
MongoDb 3.6 이상 에서는 필드 이름에서 점 과 달러 를 모두 지원 합니다. JIRA 아래 참조 : https://jira.mongodb.org/browse/JAVA-2810
Mongodb를 3.6 이상으로 업그레이드하는 것이 가장 좋은 방법입니다.
각 객체 키에 대해 JavaScript에서 다음 이스케이프를 사용합니다.
key.replace(/\\/g, '\\\\').replace(/^\$/, '\\$').replace(/\./g, '\\_')
내가 좋아하는 점은 $
처음 에만 교체 하고 콘솔에서 사용하기 까다로울 수있는 유니 코드 문자를 사용하지 않는다는 것입니다. _
나에게 유니 코드 문자보다 훨씬 더 읽기 쉽다. 또한 한 세트의 특수 문자 ( $
, .
)를 다른 세트 (유니 코드)로 바꾸지 않습니다. 그러나 전통적인 \
.
완벽하지는 않지만 대부분의 상황에서 작동합니다. 금지 된 문자를 다른 것으로 대체합니다. 키에 있기 때문에 이러한 새 문자는 상당히 드뭅니다.
/** 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": {}
}
}
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);
You can store it as it is and convert to pretty after
I wrote this example on Livescript. You can use livescript.net website to eval it
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
It will produce
{"field.field1":1,
"field.field2":2,
"field.field3":5,
"field.nested.more":1,
"field.nested.moresdafasdf":23423,
"field3":3}
Give you my tip: You can using JSON.stringify to save Object/ Array contains the key name has dots, then parse string to Object with JSON.parse to process when get data from database
Another workaround: Restructure your schema like:
key : {
"keyName": "a.b"
"value": [Array]
}
Latest MongoDB does support keys with a dot, but java MongoDB-driver is not supporting. So to make it work in Java, I pulled code from github repo of java-mongo-driver and made changes accordingly in their isValid Key function, created new jar out of it, using it now.
Replace the dot(.
) or dollar($
) with other characters that will never used in the real document. And restore the dot(.
) or dollar($
) when retrieving the document. The strategy won't influence the data that user read.
You can select the character from all characters.
The strange this is, using mongojs, I can create a document with a dot if I set the _id myself, however I cannot create a document when the _id is generated:
Does work:
db.testcollection.save({"_id": "testdocument", "dot.ted.": "value"}, (err, res) => {
console.log(err, res);
});
Does not work:
db.testcollection.save({"dot.ted": "value"}, (err, res) => {
console.log(err, res);
});
I first thought dat updating a document with a dot key also worked, but its identifying the dot as a subkey!
Seeing how mongojs handles the dot (subkey), I'm going to make sure my keys don't contain a dot.
/home/user/anaconda3/lib/python3.6/site-packages/pymongo/collection.py
Found it in error messages. If you use anaconda
(find the correspondent file if not), simply change the value from check_keys = True
to False
in the file stated above. That'll work!
참고URL : https://stackoverflow.com/questions/12397118/mongodb-dot-in-key-name
'programing' 카테고리의 다른 글
초기화되지 않은 지역 변수를 사용하여 해당 변수 유형의 정적 콘텐츠에 액세스 할 수없는 이유는 무엇입니까? (0) | 2020.11.05 |
---|---|
자바 스크립트-객체 키-> 값 (0) | 2020.11.05 |
블록 범위가 원래 JavaScript에서 구현되지 않은 이유는 무엇입니까? (0) | 2020.11.04 |
pypi는 이전 버전의 패키지를 참조하십시오. (0) | 2020.11.04 |
Android Studio : Gradle 실행을 완료하지 못했습니다. 원인이 비어 있습니다. (0) | 2020.11.04 |