Javascript 键名中的 MongoDB 点 (.)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12397118/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 07:53:30  来源:igfitidea点击:

MongoDB dot (.) in key name

javascriptmongodbnosql

提问by Michael Yagudaev

It seems mongo does not allow insertion of keys with a dot (.) or dollar sign ($) however when I imported a JSON file that contained a dot in it using the mongoimport tool it worked fine. The driver is complaining about trying to insert that element.

似乎 mongo 不允许插入带有点 (.) 或美元符号 ($) 的键,但是当我使用 mongoimport 工具导入一个包含点的 JSON 文件时,它工作正常。驱动程序抱怨试图插入该元素。

This is what the document looks like in the database:

这是文档在数据库中的样子:

{
    "_id": {
        "$oid": "..."
    },
    "make": "saab",
    "models": {
        "9.7x": [
            2007,
            2008,
            2009,
            2010
        ]
    }
}

Am I doing this all wrong and should not be using hash maps like that with external data (i.e. the models) or can I escape the dot somehow? Maybe I am thinking too much Javascript-like.

我做这一切都错了吗,不应该像这样使用带有外部数据(即模型)的哈希映射,或者我可以以某种方式逃避点吗?也许我在想太多类似 Javascript 的东西。

采纳答案by JohnnyHK

MongoDB doesn't support keys with a dotin them so you're going to have to preprocess your JSON file to remove/replace them before importing it or you'll be setting yourself up for all sorts of problems.

MongoDB 不支持其中带有点的键,因此您将不得不预处理您的 JSON 文件以在导入之前删除/替换它们,否则您将面临各种问题。

There isn't a standard workaround to this issue, the best approach is too dependent upon the specifics of the situation. But I'd avoid any key encoder/decoder approach if possible as you'll continue to pay the inconvenience of that in perpetuity, where a JSON restructure would presumably be a one-time cost.

这个问题没有标准的解决方法,最好的方法太依赖于具体情况。但是如果可能的话,我会避免使用任何关键的编码器/解码器方法,因为您将继续永久地支付这种不便,其中 JSON 重组可能是一次性成本。

回答by Steve Eynon

As mentioned in other answers MongoDB does not allow $or .characters as map keys due to restrictions on field names. However, as mentioned in Dollar Sign Operator Escapingthis restriction does not prevent you from insertingdocuments with such keys, it just prevents you from updating or querying them.

正如其他答案中提到的,由于字段名称的限制,MongoDB 不允许$.字符作为映射键。但是,正如美元符号运算符逃避此限制中所述,不会阻止您插入带有此类密钥的文档,它只会阻止您更新或查询它们。

The problem of simply replacing .with [dot]or U+FF0E(as mentioned elsewhere on this page) is, what happens when the user legitimately wants to store the key [dot]or U+FF0E?

简单地替换.[dot]or U+FF0E(如本页其他地方所述)的问题是,当用户合法地想要存储密钥[dot]or时会发生什么U+FF0E

An approach that Fantom'safMorphia drivertakes, is to use unicode escape sequences similar to that of Java, but ensuring the escape character is escaped first. In essence, the following string replacements are made (*):

Fantom 的afMorphia 驱动程序采用的一种方法是使用类似于 Java 的 unicode 转义序列,但确保首先转义转义字符。本质上,进行了以下字符串替换 (*):

\  -->  \
$  -->  \u0024
.  -->  \u002e

A reverse replacement is made when map keys are subsequently read fromMongoDB.

当随后MongoDB读取映射键时,会进行反向替换。

Or in Fantomcode:

或者在Fantom代码中:

Str encodeKey(Str key) {
    return key.replace("\", "\\").replace("$", "\u0024").replace(".", "\u002e")
}

Str decodeKey(Str key) {
    return key.replace("\u002e", ".").replace("\u0024", "$").replace("\\", "\")
}

The only time a user needs to be aware of such conversions is when constructing queries for such keys.

用户需要了解此类转换的唯一时间是在为此类键构建查询时。

Given it is common to store dotted.property.namesin databases for configuration purposes I believe this approach is preferable to simply banning all such map keys.

鉴于dotted.property.names出于配置目的将存储在数据库中是很常见的,我相信这种方法比简单地禁止所有此类映射键更可取。

(*) afMorphia actually performs full / proper unicode escaping rules as mentioned in Unicode escape syntax in Javabut the described replacement sequence works just as well.

(*) afMorphia 实际上执行完整/正确的 Unicode 转义规则,如Java中的Unicode 转义语法中所述但所描述的替换序列也同样有效。

回答by Martin Konecny

The Mongo docssuggest replacing illegal characters such as $and .with their unicode equivalents.

蒙戈文档建议替换非法字符,如$.他们的Unicode的等价物。

In these situations, keys will need to substitute the reserved $ and . characters. Any character is sufficient, but consider using the Unicode full width equivalents: U+FF04 (i.e. “$”) and U+FF0E (i.e. “.”).

在这些情况下,键需要替换保留的 $ 和 。人物。任何字符都可以,但请考虑使用 Unicode 全角等价物:U+FF04(即“$”)和 U+FF0E(即“.”)。

回答by h4ck3d

The latest stable version (v3.6.1) of the MongoDB does support dots (.) in the keys or field names now.

MongoDB 的最新稳定版本 (v3.6.1) 现在支持在键名或字段名中使用点 (.)。

Field names can contain dots (.) and dollar ($) characters now

字段名称现在可以包含点 (.) 和美元 ($) 字符

回答by Steve

A solution I just implemented that I'm really happy with involves splitting the key name and value into two separate fields. This way, I can keep the characters exactly the same, and not worry about any of those parsing nightmares. The doc would look like:

我刚刚实现的一个我非常满意的解决方案涉及将键名和值拆分为两个单独的字段。这样,我可以保持字符完全相同,而不必担心任何解析噩梦。文档看起来像:

{
    ...
    keyName: "domain.com",
    keyValue: "unregistered",
    ...
}

You can still query this easy enough, just by doing a findon the fields keyNameandkeyValue.

您仍然可以很容易地进行查询,只需findkeyNamekeyValue字段上执行 a 即可。

So instead of:

所以而不是:

 db.collection.find({"domain.com":"unregistered"})

which wouldn't actually work as expected, you would run:

这实际上不会按预期工作,您将运行:

db.collection.find({keyName:"domain.com", keyValue:"unregistered"})

and it will return the expected document.

它将返回预期的文档。

回答by Henry

You can try using a hash in the key instead of the value, and then store that value in the JSON value.

您可以尝试在键中使用哈希而不是值,然后将该值存储在 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
    ]
}

You would then access the models using the hash later.

然后,您稍后将使用哈希访问模型。

var version = "9.7x";
collection.find( { _id : ...}, function(e, data ) {
    var models = data.models[ md5(version) ];
}

回答by Abhidemon

It is supported now

现在支持

MongoDb 3.6onwards supports both dotsand dollarin field names. See below JIRA: https://jira.mongodb.org/browse/JAVA-2810

MongoDb 3.6以后的字段名称支持美元。请参阅以下 JIRA:https: //jira.mongodb.org/browse/JAVA-2810

Upgrading your Mongodb to 3.6+ sounds like the best way to go.

将您的 Mongodb 升级到 3.6+ 听起来是最好的方法。

回答by maerics

From the MongoDB docs"the '.' character must not appear anywhere in the key name". It looks like you'll have to come up with an encoding scheme or do without.

来自MongoDB 文档“'.' 字符不得出现在键名中的任何位置”。看起来您必须想出一个编码方案,否则就不用。

回答by B T

You'll need to escape the keys. Since it seems most people don't know how to properly escape strings, here's the steps:

你需要逃脱钥匙。由于似乎大多数人不知道如何正确转义字符串,因此步骤如下:

  1. choose an escape character (best to choose a character that's rarely used). Eg. '~'
  2. To escape, first replace all instances of the escape character with some sequence prepended with your escape character (eg '~' -> '~t'), then replace whatever character or sequence you need to escape with some sequence prepended with your escape character. Eg. '.' -> '~p'
  3. To unescape, first remove the escape sequence from all instance of your second escape sequence (eg '~p' -> '.'), then transform your escape character sequence to a single escape character(eg '~s' -> '~')
  1. 选择一个转义字符(最好选择一个很少使用的字符)。例如。'~'
  2. 要转义,首先将转义字符的所有实例替换为以您的转义字符开头的某个序列(例如,'~' -> '~t'),然后将您需要转义的任何字符或序列替换为以您的转义字符开头的某个序列. 例如。'.' -> '~p'
  3. 要取消转义,首先从第二个转义序列的所有实例中删除转义序列(例如 '~p' -> '.'),然后将转义字符序列转换为单个转义字符(例如 '~s' -> '~ ')

Also, remember that mongo also doesn't allow keys to start with '$', so you have to do something similar there

另外,请记住,mongo 也不允许键以“$”开头,因此您必须在那里做类似的事情

Here's some code that does it:

这是一些执行此操作的代码:

// 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, '~')
}

回答by PomPom

A late answer, but if you use Spring and Mongo, Spring can manage the conversion for you with MappingMongoConverter. It's the solution by JohnnyHK but handled by Spring.

一个迟到的答案,但如果您使用 Spring 和 Mongo,Spring 可以使用MappingMongoConverter. 这是 JohnnyHK 的解决方案,但由 Spring 处理。

@Autowired
private MappingMongoConverter converter;

@PostConstruct
public void configureMongo() {
 converter.setMapKeyDotReplacement("xxx");
}

If your stored Json is :

如果您存储的 Json 是:

{ "axxxb" : "value" }

Through Spring (MongoClient) it will be read as :

通过 Spring (MongoClient),它将被读取为:

{ "a.b" : "value" }