mongoDB中的Ruby和重复字段

时间:2014-01-24 12:52:52

标签: ruby mongodb

我遇到了多个具有相同名称的字段的问题。

让我们考虑以下代码:

    mongo_client = MongoClient.new("localhost", 27017)
    db = mongo_client.db("mydb")
    coll = db.collection("test")
    coll.remove

    #create an entry
    customer = {:id => 321, :name => "test customer"}
    coll.save customer

    #find the entry and modify it
    customer = coll.find(:id => 321).to_a.first
    customer[:name] = "test customer 2"
    coll.save customer

    #find again and print
    customer = coll.find(:id => 321).to_a.first
    pp customer

输出符合预期:

{"_id"=>BSON::ObjectId('52e254c5990300785b000001'),
"name"=>"test customer 2",
"id"=>321}  

robomongo 显示现在有两个名称字段: enter image description here

这很奇怪。

所以我的两个问题是:

  1. 如何修复我的数据库?
    • 修复意味着:迭代所有文件;测试两个同名的字段中哪一个是我要保留的字段;删除错误的字段并再次保存文档。
    • 这里的问题是我无法访问两个同名的字段,因为文档被映射到ruby哈希...
  2. 我怎样才能首先防止这种情况发生?

3 个答案:

答案 0 :(得分:3)

我无法直接回答您的问题,但可以解释为什么您只在Ruby程序中看到一个带有“name”的字段,而Robomongo则显示两个字段:

请查看此页面上的“字段名称”部分:http://docs.mongodb.org/manual/core/document/

它说:

  

BSON文档可能有多个具有相同名称的字段。最   但是,MongoDB接口代表具有结构的MongoDB(例如,   哈希表),不支持重复的字段名称。如果你需要   操纵具有多个具有相同字段的文档   名称,请参阅驱动程序的驱动程序文档。

     

内部MongoDB进程创建的一些文档可能有   重复字段,但没有MongoDB进程会添加重复   字段到现有用户文档。

所以看起来你的MongoDB for Ruby会将文档映射到不支持重复字段名称的哈希结构。

也许暂时切换到Robomongo使用的驱动程序可以帮助解决您的问题。之后,您可以返回使用MongoDB。

根据您的MongoDB版本,我认为您可以通过将--objcheck传递到mongod进程来阻止文档中的重复字段名称。

摘自手册:

  

- objcheck强制mongod在收到客户端时验证所有请求,以确保客户端永远不会插入无效文档   进入数据库。对于具有高度子文档的对象   嵌套, - objcheck可以对性能产生很小的影响。您可以   set --noobjcheck在运行时禁用对象检查。改变了   版本2.4:MongoDB默认启用--objcheck,以防止任何   客户端将错误或无效的BSON插入MongoDB   数据库中。

我希望这有帮助!

答案 1 :(得分:1)

以下C ++代码将连接到您的本地MongoDB服务器,并将BSON文档插入 tutorial.persons 集合中。创建的文档具有重复的键(“名称”使用两次)。当我们查询所有人的集合并显示每个文档的字段时,您将看到“名称”字段出现两次。

这证明C ++ MongoDB驱动程序可能更适合于多次使用相同字段名称的插入查询文档。

#include "mongo/client/dbclient.h"
#include <iostream>

void show_all_persons(mongo::DBClientConnection & c) {
    // Iterate over the collection in which we've just inserted the person object
    std::auto_ptr<mongo::DBClientCursor> cursor = c.query("tutorial.persons", mongo::BSONObj());
    while (cursor->more()) {
        mongo::BSONObj d = cursor->next();
        std::cout   << "The document " 
                    << d.toString() 
                    << " contains " << d.nFields() << " field(s)."
                    << std::endl;
    }
}

int main() {
  try {
    // Connect
    mongo::DBClientConnection c;
    c.connect("localhost");    
    // Prepare BSON "person" document to insert (notice duplicate key "name")
    mongo::BSONObj p = BSON( "name" << "Alice" << "name" << "Bob" );
    c.insert("tutorial.persons", p);        
    show_all_persons(c);
  } catch( const mongo::DBException &e ) {
    std::cout << "caught " << e.what() << std::endl;
  }
  return EXIT_SUCCESS;
}

以上是运行上述代码时的输出:

The document { _id: ObjectId('52e282cd84a7df0a1975eb8b'), name: "Alice", name: "Bob" } contains 3 field(s).

您可以使用这个hacky CMakeLists.txt文件进行编译:

project(bsoncpp)
cmake_minimum_required(VERSION 2.8)
aux_source_directory(. SRC_LIST)
include_directories(${Boost_INCLUDE_DIRS})
link_directories(${Boost_LIBRARY_DIRS})
add_executable(bsoncpp ${SRC_LIST})
target_link_libraries(bsoncpp /usr/lib/libmongoclient.a -lboost_system -lboost_thread -lboost_filesystem -lpthread -lssl -lcrypto)

我希望这会有所帮助。现在由您来删除不需要的重复字段。

玩得开心!

答案 2 :(得分:1)

我使用代码来回答我的问题 2)我怎样才能首先防止这种情况?是:使用方法 Mongo :: Collection的组合: :更新和操作 $ set

示例代码:

mongo_client = MongoClient.new("localhost", 27017)
db = mongo_client.db("mydb")
coll = db.collection("test")
coll.remove

#create an entry
customer = {:id => 321, :name => "test customer"}
coll.save customer

#Now comes the important part! find the entry and modify it
coll.update({:id => 321}, {"$set" => {:name => "test customer 2"}}, {})