Paul
Paul

Reputation: 965

How to convert the Rust Mongo driver's BSON type to ObjectId?

I'm working on a tool to sync a collection of Mongo documents to a Postgres database:

extern crate bson;
extern crate mongodb;
use mongodb::{Client, ThreadedClient};
use mongodb::db::ThreadedDatabase;

extern crate docopt;
use docopt::Docopt;

extern crate postgres;
use postgres::{Connection, SslMode};

static USAGE : &'static str = "
USAGE: user_importer  --mongo-url <mongo_url> --pg-url <pg_url>
       user_importer (--help)

Options:
  --mongo-url  Mongo Connection URI to the DB that has to users to be imported
  --pg-url   Postgres Connection URI to mizuna's DB
  -h, --help        Show this message
";

fn main() {
  let argv = std::env::args();
  let args = Docopt::new(USAGE).and_then(|d| d.argv(argv).parse()).unwrap_or_else(|e| e.exit());

  let mongo_url = args.get_str("<mongo_url>");
  let pg_url = args.get_str("<pg_url>");

  let pg = Connection::connect(pg_url, SslMode::None).unwrap();
  let stmt = pg.prepare("INSERT INTO mongo_users (mongo_id, email, name, sfdc_id) VALUES ($1, $2, $3, $4)").unwrap();

  let mongo = Client::with_uri(mongo_url)
             .ok().expect("Failed to initialize client.");
  let coll = mongo.db("napa").collection("users");
  let cursor = coll.find(None, None).unwrap();

  for result in cursor {
    if let Ok(item) = result {
      println!("{:?}", item.get("_id").unwrap());
      println!("to_string {:?}", item.get("_id").unwrap().to_string());
      println!("to_json {:?}", item.get("_id").unwrap().to_json());
      let mongo_id  = item.get("_id").unwrap().to_string();
      let email     = item.get("email").map(|s| s.to_string());
      let name      = item.get("name").map(|s| s.to_string());
      let sfdc_id   = item.get("sfdc_id").map(|s| s.to_string());


      stmt.execute(&[&mongo_id, &email, &name, &sfdc_id]).unwrap();
    }
  }
}

(Playground)

The part I'm having trouble with is converting the document's _id field to a hex string (Line 43). It seems that item.get("_id") returns an object of type BSON, which has a few converters: to_string() returns ObjectId("566740710ed3bc0a8f000001"), and to_json() returns {"$oid": "566740710ed3bc0a8f000001"}, neither of which are the plan hex string that I want to insert. I see in the docs that ObjectId has a to_hex() function, but I can't figure out how to get from the get() method's BSON return type to the underlying ObjectId type that has that method implemented.

Upvotes: 1

Views: 4021

Answers (3)

Barrrettt
Barrrettt

Reputation: 819

With serde data model example.

let id: ObjectId = customer.id.unwrap();
let str_id: String = id.to_hex();

One line.

let str_id = customer.id.unwrap().to_hex();   

The model example definition:

#[derive(Serialize, Deserialize)]
pub struct Customer {
    #[serde(rename = "_id", skip_serializing_if = "Option::is_none")]
    pub id: Option<ObjectId>,
    pub name: String,
    ...
}

Upvotes: 0

Vladimir Matveev
Vladimir Matveev

Reputation: 127831

Use OrderedDocument::get_object_id() method:

let mongo_id = item.get_object_id("_id").unwrap();
let mongo_id_hex = mongo_id.to_hex();

It is sad that bson-rs does not have any docs published anywhere.

Upvotes: 3

Francis Gagn&#233;
Francis Gagn&#233;

Reputation: 65782

The get() methods returns an Option<&Bson>. Bson is an enum, so in order to access the data in a variant, you need to use pattern matching with match or if let.

let mongo_id  =
  match *item.get("_id").unwrap() {
    Bson::ObjectId(oid) => oid,
    _ => panic!("_id is not an ObjectId!"),
  };

This initializes mongo_id with the ObjectId value for the _id field.

Upvotes: 2

Related Questions