我一直在玩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/

10-16 20:57