私はMongoDBで遊んでいて、ドメイン名で項目をキーしたいと思っています。問題は、ピリオド 'などの特殊文字を使用することです。キーがMongoをエラーで壊した:'を使用する慣用方法は何ですか? (または他の特殊文字)をMongoDBのキーで使用しますか?
エラー:キーwww.google.comに '。'が含まれていてはいけません。
例えば、私が保存できるようにしたい:
stupidObject = {
'www.google.com': {
'8.8.8.8': 'Other info',
'8.8.4.4': ['item1', 'item2', ... , 'itemN']
},
'www.othersite.com': {
'8.8.8.8': 'Other info',
'8.8.4.4': ['item1', 'item2', ... , 'itemN']
},
}
私が見てきたソリューションのすべてのいくつかの変種です:保存する前にキーをハッシュ、Unicode表現を使用し、保存する前にキーを変更。例えば回答を参照してください:MongoDB dot (.) in key name
これらのソリューションはすべて、独自の問題を引き起こし、コードを維持するのが難しくなります。プログラマはこのフィルタリングを行い、一貫してそれを行うことを忘れないように責任を持っています。これは厳しい解決策です。
しかし、ハッシュについては、衝突は危険です(デバッグは不可能に近づくでしょう)。そしてプログラマにも責任を負わせます。これらのソリューションが国際的な開発チームに及ぼす影響を想像してみてください。
私の質問は簡単です:MongoDBでこれを行う正しい方法は何ですか?
私は再帰的に(警鐘が!)構造をナビゲートして特殊文字を置き換えるカスタムソリューションを完成させました。これは、pre( 'save')とpost( 'find')フックを利用してMongoose Schemaで行われます。
これは、プログラマが保存するドメイン名を持つキーを使用する特殊文字を気にする必要がなくなり、データベース層がすべてを透過的に処理することを意味します。これは私にとってより良い解決策のようです。
しかし...これは、hasOwnPropertyを使用するときに誤ったMongooseオブジェクトの問題を回避するために、そして、 '.toObject()'を最初に実行し、元の 'this'ポインタを参照渡しするという要件を回避する必要があります。
この解決策は機能しますが、より良い方法が必要であると私は考えました!これを行う正しい方法に関する考えや指導は感謝して受け入れられます!下のコードを見ると、より良い方法が必要だと思う理由がわかります!
私は、この問題を解決するために、ライブラリをインストールしたり、他の依存関係を持っていないことを言及する必要があります。
は、ここで使用されるコードの例です:
// Recursive function to replace character||string in keys that may cause violations
// Same code can be used to reverse the change
//
var replaceStringInKeys = function (stringToReplace, newString, regExp, thisObj, thisPtr) {
for(property in thisObj) {
if (thisObj.hasOwnProperty(property)) {
if(property.indexOf(stringToReplace) > -1) {
// Replace the '.'s with URL escaped version. Delete old object.
var newproperty = property.replace(regExp, newString);
thisObj[newproperty] = thisObj[property];
thisPtr[newproperty] = thisPtr[property];
delete thisObj[property];
delete thisPtr[property];
// Pass the new property too
if (thisObj[newproperty].constructor === Object) {
thisObj[newproperty] = replaceStringInKeys(stringToReplace, newString, regExp, thisObj[newproperty], thisPtr[newproperty]);
thisPtr[newproperty] = thisObj[newproperty];
}
continue;
}
if (thisObj[property].constructor === Object) {
thisObj[property] = replaceStringInKeys(stringToReplace, newString, regExp, thisObj[property], thisPtr[property]);
thisPtr[property] = thisObj[property];
}
}
}
return thisObj;
};
testSchema.pre('save', function(next) {
// Calling '.toObject' allows for hasOwnProperty to work
var thisObj = this.toObject();
console.log('Pre save record...');
// Duplicate the this pointer as mongo is too shit to use hasOwnProperty properly
replaceStringInKeys('.', '[whateveryouwantinsteadofdot]', /\./g, thisObj, this);
next();
});
testSchema.post('find', function(results) {
console.log('post find record...');
// Undo the changes made by the pre-save hook
var i;
for(i = 0; i < results.length; i++) {
var thisObj = results[i].toObject();
replaceStringInKeys('[whateveryouwantinsteadofdot]', '.', /\[whateveryouwantinsteadofdot\]/g, thisObj, results[i]);
}
});
注:このソリューションを使用して注意してください(あなたが十分にクレイジーだ場合)セキュリティ上の問題があるかもしれないと。たとえば、悪い人があなたが '。 %2Eを使用しています。
hxxp://www.vulnerablesitethatdoesntexist.com/%2E%2E/%2E%2E/%2E%2E/%2E%2E/%2E%2E/%2E%2E/%2E%2E/%
hxxp:// WWW正しくエスケープされているが、透過的にディレクトリトラバーサルのタイプ文字列に変換されるだろう2E%の2E /%2E%2E /%2E%2E /%2E%2E/etc/passwdファイル
。 vulnerabilitiesitethatdoesntexist.com/../../../../../../../../../../../../../../../etc/passwd
は、リンクのおかげで、この答えhttp://stackoverflow.com/questions/40542336/mongodb-insert-key-with-dollar/40542724#40542724 – sergiuz
こんにちははSergiuを参照してください。私は前にその答えを読んでいた。このソリューションはバックエンドデータの卸売り変更を必要としますが、めったに良い考えではありません。上記のようにプリフックとポストフックでこの置換を行うことができますが、解決策は上記と同じです。また、キャラクターのように見えるがキャラクターでないホモグラフにデータを変更するリスクがあります。これにより、Unicodeをレンダリングする端末を介してデータを参照すると、クエリが失敗する理由を開発者が特定できない問題が発生する可能性があります。 – misterfitzy