我一直在玩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']
},
}
我看到的所有解决方案都是一些变体:在保存之前更改密钥,使用unicode表示,在保存之前散列密钥。例如,请参见答案:MongoDB dot (.) in key name
所有这些解决方案都会导致它们自己的问题,并使代码难以维护。程序员的责任是记住要进行过滤,并且要始终如一地进行过滤。这是一个糟糕的解决办法。
我想是关于散列的,但冲突是一个风险(这几乎不可能调试),再次把责任推给程序员。想象一下这些解决方案对国际开发团队的影响。
我的问题很简单:在MongoDB中正确的方法是什么?
我最终得到了一个定制的解决方案,在这里我递归地(警铃!)导航结构并替换特殊字符。这在Mongoose模式中通过利用pre('save')和post('find')钩子完成。
这意味着程序员不必关心他们在保存域名时使用的键的特殊字符,数据库层透明地处理所有事情。这对我来说似乎是个更好的解决办法。
然而。。。这需要一些混乱的代码来解决Mongoose对象在使用HasOwnProperty和运行“.tooObject()”的要求时行为不正常的问题,然后通过引用传递原始的“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.vulnerablestathadoesntexist.com/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/etc/passwd
已正确转义,但将透明地转换为目录遍历类型字符串:
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']}
]
}
关于node.js - 使用'。'的惯用方法是什么? MongoDB key 中的(或其他特殊字符)?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/43607645/