什么是惯用的方式使用'。' (或其他特殊字符)在MongoDB的密钥?

我一直在玩MongoDB,并希望通过域名关键项目。 问题是使用特殊的字符,如句点'。' 对于键错误的Mongo与错误:

错误: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'] }, } 

我见过的所有解决scheme都是一些变体:在保存之前更改密钥,使用Unicode表示forms,在保存之前对密钥进行哈希处理。 在密钥名中查看答案: MongoDB点(。)

所有这些解决scheme都会导致他们自己的问题,并且难以维护代码。 程序员的责任是记住要做这个过滤并一致地执行。 这是一个可怕的解决scheme。

我虽然关于哈希,但碰撞是一个风险(这几乎不可能debugging),并再次对程序员负责。 想象一下这些解决scheme对国际开发团队的影响。

我的问题很简单:在MongoDB中这样做的正确方法是什么?

我结束了自定义的解决scheme,我recursion(警钟!)导航结构,并replace特殊字符。 这是通过利用pre('save')和post('find')钩子在Mongoose Schema中完成的。

这意味着程序员不必关心他们使用密钥的特殊字符和他们保存的域名,而数据库层则透明地处理所有的事情。 这对我来说似乎是一个更好的解决scheme。

然而…这需要一些凌乱的代码来解决使用hasOwnProperty时Mongoose对象行为不当的问题,并要求首先运行“.toObject()”,然后通过引用传递原来的“this”指针。

这个解决scheme的工作,但我觉得必须有更好的方法! 任何想法或指导正确的方式来做到这一点是感激地接受! 当你看到下面的代码,你会明白为什么我认为必须有一个更好的方法!

我应该提到我不想安装任何库或有其他依赖项来解决这个问题。

以下是使用的代码示例:

 // 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]); } }); 

注意:小心使用这个解决scheme(如果你足够疯狂),因为可能存在安全问题。 例如,如果一个坏人知道你取代'。' 与%2E,他们可以强制使用例如

hxxp://www.vulnerablesitethatdoesntexist.com/%2E%2E/%2E%2E/%2E%2E/%2E%2E/%2E%2E/%2E%2E/%2E%2E/%2E%2E/ %2E%2E /%2E%2E /%2E%2E / etc / passwd中

这是正确转义,但将被透明地转换为目录遍历typesstring:
hxxp://www.vulnerablesitethatdoesntexist.com/../../../../../../../../../../../etc/passwd

你应该改变你的文件的结构,使用点作为关键的无效。 几年前我遇到了同样的问题。

 yourStupidObject = { 'www.google.com': [ {'ip': '8.8.8.8', more: 'Other info', {'ip': '8.8.4.4', more: ['item1']} ] }