Если я пытаюсь вставить документ в MongoDB с ключом, начинающимся с $
Я получаю сообщение об ошибке:
> db.x.insert({"a": {"$b": "1"}})
2016-09-29T21:14:23.078+0200 E QUERY [thread1] Error: field names cannot start with $ [$b] :
...
(У меня есть наблюдатель аналогичного поведения с использованием драйвера Node.js)
Тем не менее, работает следующая программа C ++:
#include <cstdlib>
#include <iostream>
#include "mongo/client/dbclient.h" // for the driver
// compile with: g++ test.cpp -pthread -lmongoclient -lboost_thread -lboost_system -lboost_regex -o test
void run() {
mongo::DBClientConnection c;
c.connect("localhost");
mongo::BSONObj doc = BSON("a" << BSON("$b" << 1));
c.insert("test.x", doc);
}
int main() {
mongo::client::initialize();
try {
run();
} catch( const mongo::DBException &e ) {
std::cout << "caught " << e.what() << std::endl;
}
return EXIT_SUCCESS;
}
Я могу вставить его, как find()
показывает:
> db.x.find()
{ "_id" : ObjectId("57ed67fdbf3a716e16f6d102"), "a" : { "$b" : 1 } }
Таким образом, похоже, что драйвер C ++ способен «обойти» описанные правила структуры документа в документации MongoDB. Есть ли объяснение этому поведению? Это может каким-то образом «сломать» базу данных MongoDB (я полагаю, что это ограничение имеет вескую причину, и наличие документов в БД, не соблюдающих его, может быть проблематичным)
Я заметил, что это происходит только тогда, когда ключ с $
не на первом уровне. Например, если я использую
mongo::BSONObj doc = BSON("$b" << 1);
тогда я получаю постоянную ошибку
caught OperationException: { index: 0, code: 2, errmsg: "Document can't have $ prefixed field names: $b", op: { _id: ObjectId('57ed6a015365c193cbbb3231'), $b: 1 } }
На всякий случай я использую MongoDB 3.2.0 и устаревший драйвер C ++ 1.0.7.
Начиная с MongoDB 3.2, сервер выполняет некоторую проверку правильности имен ключей во время вставки (в том числе запрещает им начинаться со знака доллара) на верхнем уровне документа, но не проверяет имена ключей в поддокументах. Увидеть https://jira.mongodb.org/browse/SERVER-10987 для отслеживания заявки запрос на проверку имен ключей в под-документах.
Некоторые драйверы выполняют дополнительную проверку имени ключа (например, оболочка и драйвер Node.js проверяют наличие символов доллара в начале всех ключей в документах для вставки), но набор правил проверки в настоящее время не согласован между драйверами. По совпадению, в JIRA на JIRA поступил относительно недавний тикет, поданный в проекте DRIVERS (который используется для согласованного согласования новых функций и улучшений согласованным образом во всех драйверах). https://jira.mongodb.org/browse/DRIVERS-308, которая включает в себя попытку указать, какая проверка на стороне клиента должна быть выполнена во время вставки. Если этот тикет в конечном итоге движется вперед, то исправление непременно войдет в последнюю версию драйвера C ++ (обратите внимание, что устаревший драйвер в настоящее время получает только критические исправления ошибок).
Что касается названий ключей со знаками доллара: сервер будет хорошо хранить и извлекать их, но они не будут хорошо работать с другими функциями базы данных. Смотрите, например:
> db.version()
3.2.10
> db.collection.find()
{ "_id" : 1, "a" : { "$b" : 1 } }
> db.collection.update({_id: 1}, {$set: {"a.$b": 2}})
WriteResult({
"nMatched" : 0,
"nUpserted" : 0,
"nModified" : 0,
"writeError" : {
"code" : 52,
"errmsg" : "The dollar ($) prefixed field '$b' in 'a.$b' is not valid for storage."}
})
Других решений пока нет …