mongodb - Rust 更新 mongo 文档
问题描述
我正在尝试更新我的文档,如果我没有传递一个字段,它将被删除。
我的文件是
{
"_id":"27fc47a4-0730-446c-8acd-41aa6e227406",
"user_id":"a07c8c2f-e83a-47f7-80dc-a18407f997e1",
"pet":{
"name":"Hello",
"bio":"Hello",
"gender":"Male",
"can_live_with_other_cats":true,
"can_live_with_other_dogs":true
},
"status":"Pending",
"created_at":{
"$date":"2021-11-06T22:30:41.977Z"
}
}
我试图更新
"pet":{
"name":"Hello",
"bio":"Hello",
"gender":"Male",
},
"status":"Pending",
"created_at":{
"$date":"2021-11-06T22:30:41.977Z"
}
他正在删除 "can_live_with_other_cats":true 和 "can_live_with_other_dogs":true
如何在不删除我的字段的情况下更新?
async fn update(&self, adoption: &dto::adoption::update::Adoption) -> Result<(), Error> {
let mongo_collection = MongoClient::get_collection("adoptions").await;
let mongo_model = datamodel::insert_adoption::PetDataModel::from(&adoption.pet);
let query = doc! {"_id": adoption.id.to_string()};
let doc = mongodb::bson::to_document(&mongo_model).unwrap();
println!("{}", doc);
let update = doc!{"$set": {"pet": doc} };
mongo_collection
.update_one(query, update, None)
.await
.map(|_| ())
.map_err(|e| domain::errors::Error::internal_server_error(e.to_string()))
}
我要更新的结构
pub struct PetDataModel {
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub bio: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub gender: Option<GenderDataModel>,
#[serde(skip_serializing_if = "Option::is_none")]
pub can_live_with_other_cats: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub can_live_with_other_dogs: Option<bool>,
}
非常感谢
解决方案
$set
使用根据示例提供的值覆盖键,传递对象将pet
使用提供的不包含键的对象覆盖键。
"pet":{
"name":"Hello",
"bio":"Hello",
"gender":"Male"
},
"status":"Pending",
"created_at":{
"$date":"2021-11-06T22:30:41.977Z"
}
要在不覆盖现有密钥的情况下进行更新,您可以使用以下格式显示
例如:
"pet.name":"Hello",
"pet.bio":"Hello",
"pet.gender":"Male"
"pet.status":"Pending",
"pet.created_at.$date": "2021-11-06T22:30:41.977Z"
正如@Renato 在评论中所说,我们也可以使用 serterename
属性
pub struct PetDataModel {
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(rename = "pet.name")]
pub name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(rename = "pet.bio")]
pub bio: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(rename = "pet.gender")]
pub gender: Option<GenderDataModel>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(rename = "pet.can_live_with_other_cats")]
pub can_live_with_other_cats: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(rename = "pet.can_live_with_other_dogs")]
pub can_live_with_other_dogs: Option<bool>,
}
或者
您可以使用此代码rust-flatten-json
来展平 json
#[macro_use]
extern crate serde_json;
#[macro_use]
extern crate error_chain;
use serde_json::value::Value;
use serde_json::map::Map;
error_chain! {
foreign_links {
Json(::serde_json::Error);
}
}
pub fn flatten(nested_value: &Value, flat_value: &mut Value, parent_key: Option<String>, infer_type: bool, separator: Option<&str>) -> Result<()> {
// if object
if let Some(nested_dict) = nested_value.as_object() {
flatten_object(flat_value, &parent_key, nested_dict, infer_type, separator)?;
} else if let Some(v_array) = nested_value.as_array() {
let new_k = parent_key.unwrap_or_else(||String::from(""));
flatten_array(flat_value, &new_k, v_array, infer_type, separator)?;
} else {
error!("Expected object, found something else: {:?}", nested_value)
}
Ok(())
}
fn flatten_object(flat_value: &mut Value, parent_key: &Option<String>, nested_dict: &Map<String, Value>, infer_type: bool, separator: Option<&str>) -> Result<()> {
let sep = if let Some(sep) = separator {
sep
} else {
"."
};
for (k, v) in nested_dict.iter() {
let new_k = match parent_key {
Some(ref key) => format!("{}{}{}", key, sep, k),
None => k.clone()
};
// if nested value is object recurse with parent_key
if let Some(obj) = v.as_object() {
flatten_object(flat_value, &Some(new_k), obj, infer_type, separator)?;
// if array
} else if let Some(v_array) = v.as_array() {
// if array is not empty
if !v_array.is_empty() {
// traverse array
flatten_array(flat_value, &new_k, v_array, infer_type, separator)?;
// if array is empty insert empty array into flat_value
} else if let Some(value) = flat_value.as_object_mut() {
let empty: Vec<Value> = vec!();
value.insert(k.to_string(), json!(empty));
}
// if no object or array insert value into the flat_value we're building
} else if let Some(value) = flat_value.as_object_mut() {
infer_type_and_insert(v, new_k, value, infer_type)?;
}
}
Ok(())
}
fn infer_type_and_insert(v: &Value, new_k: String, value: &mut Map<String, Value>, infer_type: bool) -> Result<()> {
let new_val;
if infer_type {
if let Some(string) = v.as_str() {
new_val = match string.parse::<i64>() {
Ok(i) => serde_json::to_value(i)?,
Err(_) => match string.parse::<f64>() {
Ok(f) => serde_json::to_value(f)?,
Err(_) => match string.parse::<bool>() {
Ok(b) => serde_json::to_value(b)?,
Err(_) => serde_json::to_value(string)?
}
}
};
} else {
new_val = v.clone();
}
} else {
new_val = v.clone();
};
value.insert(new_k, new_val);
Ok(())
}
fn flatten_array(flat_value: &mut Value, new_k: &str, v_array: &[Value], infer_type: bool, separator: Option<&str>) -> Result<()> {
for (i, obj) in v_array.iter().enumerate() {
let array_key = format!("{}.{}", new_k, i);
// if element is object or array recurse
if obj.is_object() | obj.is_array() {
flatten(obj, flat_value, Some(array_key), infer_type, separator)?;
// else insert value in the flat_value we're building
} else if let Some(value) = flat_value.as_object_mut() {
infer_type_and_insert(obj, array_key, value, infer_type)?;
}
}
Ok(())
}
let value: Value = match serde_json::from_str(&input) {
Ok(value) => value,
Err(e) => {
error!("{}", &input);
panic!("{}", e);
}
};
let mut flat_value: Value = json!({});
flatten(&value, &mut flat_value, None, true, None)?;
serde_json::to_string(&flat_value)?
推荐阅读
- node.js - 使用 import 而不是 require() 时带有 uuid 的 MongooseError
- sql - 如何在 Microsoft SQL 中使用随机位置的相似字符进行搜索?
- python - 如何在 Django 中显示 Excel 工作表?
- python - Tensorflow Keras 模型在 CPU 上工作,但不适用于 GPU
- c - 程序不将数组写入文件
- php - Laravel:同一张桌子上的关系
- javascript - 无法在选择框中选择值
- ruby - 如何测试线程
- java - notifyDataSetChanged 在适配器上不起作用
- json - 用 JSONPath 提取整个 JSON?