green_barrel/migration.rs
1//! Migrations are Green Barrel’s way of
2//! propagating changes you make to
3//! your models (adding a field, deleting a collection, etc.) into
4//! your database schema.
5
6use chrono::Utc;
7use futures::stream::TryStreamExt;
8use mongodb::{
9 bson::{
10 de::from_document,
11 doc,
12 document::Document,
13 ser::{to_bson, to_document},
14 Bson,
15 },
16 Client, Database,
17};
18use regex::Regex;
19use serde::{Deserialize, Serialize};
20use std::{collections::HashMap, error::Error, path::Path};
21
22use crate::{
23 models::helpers::{FileData, ImageData},
24 store::METADATA,
25};
26
27// MIGRATION
28// #################################################################################################
29/// For creation and updating of a technical database.
30#[derive(Serialize, Deserialize)]
31pub struct ModelState {
32 pub database: String,
33 pub collection: String,
34 pub fields: Vec<String>,
35 pub field_type_map: HashMap<String, String>,
36 pub status: bool,
37}
38
39/// For monitoring the state of models.
40pub struct Monitor<'a> {
41 pub app_name: &'a str,
42 pub unique_app_key: &'a str,
43 pub model_key_list: Vec<String>,
44}
45
46impl<'a> Monitor<'a> {
47 /// Get the name of the technical database for a project.
48 // *********************************************************************************************
49 pub fn green_tech_name(&self) -> Result<String, Box<dyn Error>> {
50 // app_name Validation.
51 // Valid characters: _ a-z A-Z 0-9
52 // Max size: 20
53 let re = Regex::new(r"^[a-zA-Z][_a-zA-Z\d]{1,20}$")?;
54 if !re.is_match(self.app_name) {
55 Err("app_name => \
56 Valid characters: _ a-z A-Z 0-9 and \
57 Max size: 20 ; \
58 First character: a-z A-Z")?
59 }
60 // UNIQUE_PROJECT_KEY Validation.
61 // UNIQUE_PROJECT_KEY - It is recommended not to change.
62 // Valid characters: a-z A-Z 0-9
63 // Size: 16
64 // Example: "7rzgacfqQB3B7q7T"
65 let re = Regex::new(r"^[a-zA-Z\d]{16}$")?;
66 if !re.is_match(self.unique_app_key) {
67 Err("UNIQUE_PROJECT_KEY => \
68 Valid characters: a-z A-Z 0-9 and \
69 Size: 16.")?
70 }
71 //
72 Ok(format!(
73 "green_tech__{}__{}",
74 self.app_name, self.unique_app_key
75 ))
76 }
77
78 /// Refresh models state.
79 // *********************************************************************************************
80 ///
81 /// ```
82 /// if {
83 /// If there is no technical database, it will be created.
84 /// } else {
85 /// Resets the Model's status to `false`.
86 /// }
87 /// ```
88 ///
89 async fn refresh(&self, client: &Client) -> Result<(), Box<dyn Error>> {
90 // Get the name of the technical database for a project.
91 let db_green_tech: String = self.green_tech_name()?;
92 // Collection for monitoring the state of Models.
93 let collection_models_name: &str = "monitor_models";
94 // Used to store selection items, for
95 // Fields type like selectTextDyn, selectTextMultDyn, etc.
96 let collection_dyn_fields_type: &str = "dynamic_fields";
97 //Get a list of databases.
98 let database_names = client.list_database_names(None, None).await?;
99 // Create a technical database for the project if it doesn't exist.
100 if !database_names.contains(&db_green_tech) {
101 // Create a collection for models.
102 client
103 .database(&db_green_tech)
104 .create_collection(collection_models_name, None)
105 .await?;
106 // Create a collection for fields types of `select`.
107 // (selectTextDyn, selectTextMultDyn, etc.)
108 client
109 .database(&db_green_tech)
110 .create_collection(collection_dyn_fields_type, None)
111 .await?;
112 } else {
113 // Reset models state information.
114 let green_tech_db = client.database(&db_green_tech);
115 let collection_models = green_tech_db.collection::<Document>(collection_models_name);
116 let mut cursor = collection_models.find(None, None).await?;
117 while let Some(doc) = cursor.try_next().await? {
118 let mut model_state = from_document::<ModelState>(doc)?;
119 model_state.status = false;
120 let query = doc! {
121 "database": &model_state.database,
122 "collection": &model_state.collection
123 };
124 let update = doc! {"$set": to_document(&model_state)?};
125 collection_models.update_one(query, update, None).await?;
126 }
127 }
128 //
129 Ok(())
130 }
131
132 /// Reorganize databases state
133 /// (full delete of orphaned collections and databases)
134 // *********************************************************************************************
135 async fn napalm(&self, client: &Client) -> Result<(), Box<dyn Error>> {
136 // Get the name of the technical database for a project.
137 let db_green_tech: String = self.green_tech_name()?;
138 let collection_models_name: &str = "monitor_models";
139 let collection_dyn_fields_type: &str = "dynamic_fields";
140 let green_tech_db: Database = client.database(&db_green_tech);
141 let collection_models = green_tech_db.collection::<Document>(collection_models_name);
142 let collection_dyn_fields =
143 green_tech_db.collection::<Document>(collection_dyn_fields_type);
144 // Delete orphaned Collections.
145 let mut cursor = collection_models.find(None, None).await?;
146 while let Some(doc) = cursor.try_next().await? {
147 let model_state: ModelState = from_document(doc)?;
148 if !model_state.status {
149 // Delete Collection (left without a model).
150 client
151 .database(&model_state.database)
152 .collection::<Document>(&model_state.collection)
153 .drop(None)
154 .await?;
155 // Delete a document with a record about the state of
156 // the model from the technical base.
157 let query: Document = doc! {
158 "database": &model_state.database,
159 "collection": &model_state.collection
160 };
161 collection_models.delete_one(query.clone(), None).await?;
162 collection_dyn_fields.delete_one(query, None).await?;
163 }
164 }
165 //
166 Ok(())
167 }
168
169 /// Migrating Models
170 // *********************************************************************************************
171 /// Check the changes in the models and (if necessary) apply to the database.
172 pub async fn migrat(&self, client: &Client) -> Result<(), Box<dyn Error>> {
173 // Run refresh models state.
174 self.refresh(client).await?;
175 for model_key in self.model_key_list.iter() {
176 // Get metadata of Model
177 let meta = {
178 // Get metadata store.
179 let metadata = METADATA.lock().await;
180 // Get metadata of Model.
181 if let Some(meta) = metadata.get(model_key) {
182 meta.clone()
183 } else {
184 Err(format!(
185 "Model key: `{model_key}` ; Method: `migrat()` => \
186 Failed to get data from cache.",
187 ))?
188 }
189 };
190 if !meta.is_add_doc {
191 continue;
192 }
193 // Service_name validation.
194 if !Regex::new(r"^[_a-zA-Z][_a-zA-Z\d]{1,30}$")
195 .unwrap()
196 .is_match(meta.service_name.as_str())
197 {
198 Err(format!(
199 "Model: `{}` > SERVICE_NAME => \
200 Valid characters: _ a-z A-Z 0-9 \
201 ; Max size: 30 \
202 ; First character: _ a-z A-Z",
203 meta.model_name
204 ))?;
205 }
206 // Database name validation.
207 if !Regex::new(r"^[_a-zA-Z][_a-zA-Z\d]{14,61}$")
208 .unwrap()
209 .is_match(meta.database_name.as_str())
210 {
211 Err(format!(
212 "Model: `{}` > DATABASE_NAME => \
213 Valid characters: _ a-z A-Z 0-9 \
214 ; Max size: 20 \
215 ; First character: _ a-z A-Z",
216 meta.model_name
217 ))?;
218 }
219 //
220 let fields_name = &meta.fields_name;
221 let ignore_fields = &meta.ignore_fields;
222 // List field names without `hash` and ignored fields.
223 let trunc_fields_name_list = fields_name
224 .iter()
225 .filter(|item| *item != "hash" && !ignore_fields.contains(*item))
226 .collect::<Vec<&String>>();
227 // Get the name of the technical database for a project.
228 let db_green_tech: String = self.green_tech_name()?;
229 let database_names: Vec<String> = client.list_database_names(None, None).await?;
230 // Map of default values and value types from `value (default)` attribute -
231 // <field_name, (field_type, value)>
232 let default_value_map: HashMap<String, serde_json::Value> =
233 meta.default_value_map.clone();
234 // Get map of fields types.
235 let field_type_map = &meta.field_type_map;
236 // Get truncated map of fields types.
237 let trunc_field_type_map = field_type_map.clone();
238 trunc_field_type_map
239 .clone()
240 .retain(|item, _| item != "hash" && !ignore_fields.contains(item));
241 // Get a map of fields type from the technical database,
242 // from the `monitor_models` collection for current Model.
243 let monitor_field_type_map: HashMap<String, String>;
244
245 // Check the field changes in the Model and (if required)
246 // update documents in the current Collection.
247 // -------------------------------------------------------------------------------------
248 // Get a list of current model field names from the technical database
249 // `green_barrel_keyword`.
250 let filter: Document = doc! {
251 "database": &meta.database_name,
252 "collection": &meta.collection_name
253 };
254 let model: Option<Document> = client
255 .database(&db_green_tech)
256 .collection("monitor_models")
257 .find_one(filter, None)
258 .await?;
259 if let Some(model) = model {
260 // Get a list of fields from the technical database,
261 // from the `monitor_models` collection for current Model.
262 let monitor_models_fields_name: Vec<String> = {
263 let fields: Vec<Bson> = model.get_array("fields")?.to_vec();
264 fields
265 .into_iter()
266 .map(|item| item.as_str().unwrap().to_string())
267 .collect()
268 };
269 // Get a map of fields type from the technical database,
270 // from the `monitor_models` collection for current Model.
271 monitor_field_type_map = {
272 model
273 .get_document("field_type_map")
274 .unwrap()
275 .iter()
276 .map(|item| (item.0.clone(), item.1.as_str().unwrap().to_string()))
277 .collect()
278 };
279 // Check if the set of fields in the collection of
280 // the current Model needs to be updated.
281 let mut changed_fields: Vec<&str> = Vec::new();
282 for field in trunc_fields_name_list.iter() {
283 if !monitor_models_fields_name.contains(&field.to_string())
284 || (trunc_field_type_map.get(*field).unwrap()
285 != monitor_field_type_map.get(*field).unwrap_or(&String::new()))
286 {
287 changed_fields.push(field);
288 }
289 }
290 // Start (if necessary) updating the set of fields in the current collection.
291 if !changed_fields.is_empty() {
292 // Get the database and collection of the current Model.
293 let db: Database = client.database(&meta.database_name);
294 let collection = db.collection::<Document>(&meta.collection_name);
295 // Get cursor to all documents of the current Model.
296 let mut cursor = collection.find(None, None).await?;
297 // Iterate through all documents in a current (model) collection.
298 while let Some(doc_from_db) = cursor.try_next().await? {
299 // Create temporary blank document.
300 let mut tmp_doc = Document::new();
301 // Loop over all fields of the model.
302 for (field_name, field_type) in field_type_map.iter() {
303 if field_name == "hash" || ignore_fields.contains(field_name) {
304 continue;
305 }
306 // Insert the reserved fields.
307 if field_name == "created_at" || field_name == "updated_at" {
308 if doc_from_db.contains_key(field_name) {
309 let value_from_db: Option<&Bson> = doc_from_db.get(field_name);
310 if let Some(value_from_db) = value_from_db {
311 tmp_doc.insert(field_name.to_string(), value_from_db);
312 } else {
313 Err(format!(
314 "Service: `{}` > Model: `{}` ; \
315 Method: `migrat()` => \
316 Cannot get field value from database for \
317 field `{}`.",
318 meta.service_name, meta.model_name, field_name
319 ))?
320 }
321 } else {
322 Err(format!(
323 "Service: `{}` > Model: `{}` ; Method: `migrat()` => \
324 Key `{}` was not found in the document from \
325 the database.",
326 meta.service_name, meta.model_name, field_name
327 ))?
328 }
329 //
330 continue;
331 }
332 // If the field exists, get its value.
333 if !changed_fields.contains(&field_name.as_str()) {
334 let value_from_db: Option<&Bson> = doc_from_db.get(field_name);
335 if let Some(value_from_db) = value_from_db {
336 tmp_doc.insert(field_name.to_string(), value_from_db);
337 } else {
338 Err(format!(
339 "Service: `{}` > Model: `{}` > Field: `{}` ; \
340 Method: `migrat()` => \
341 Can't get field value from database.",
342 meta.service_name, meta.model_name, field_name
343 ))?;
344 }
345 } else {
346 // If no field exists, get default value.
347 let default_value = default_value_map.get(field_name).unwrap();
348 tmp_doc.insert(
349 field_name.clone(),
350 match field_type.as_str() {
351 "ColorField" | "EmailField" | "PasswordField" | "PhoneField"| "TextField"
352 | "URLField" | "IPField" |"ChoiceTextField" | "SlugField" => {
353 if !default_value.is_null() {
354 Bson::String(default_value.as_str().unwrap().to_string())
355 } else {
356 Bson::Null
357 }
358 }
359 "DateField" => {
360 if !default_value.is_null() {
361 let val = format!("{}T00:00",default_value.as_str().unwrap());
362 if let Ok(ndt) = chrono::NaiveDateTime::parse_from_str( &val, "%Y-%m-%dT%H:%M")
363 {
364 let dt = chrono::DateTime::<Utc>::from_naive_utc_and_offset(ndt,Utc);
365 Bson::DateTime(dt.into())
366 } else {
367 Err(format!("Service: `{}` > Model: `{}` ; \
368 Method: `migrat()` => \
369 Incorrect date format. \
370 Example: 1970-02-28",
371 meta.service_name, meta.model_name
372 ))?
373 }
374 } else {
375 Bson::Null
376 }
377 }
378 "DateTimeField" | "HiddenDateTimeField" => {
379 if !default_value.is_null() {
380 let val = default_value.as_str().unwrap();
381 if let Ok(ndt) = chrono::NaiveDateTime::parse_from_str( val, "%Y-%m-%dT%H:%M")
382 {
383 let dt = chrono::DateTime::<Utc>::from_naive_utc_and_offset(ndt,Utc);
384 Bson::DateTime(dt.into())
385 } else {
386 Err(format!("Service: `{}` > Model: `{}` ; \
387 Method: `migrat()` => \
388 Incorrect date and time format. \
389 Example: 1970-02-28T00:00",
390 meta.service_name, meta.model_name
391 ))?
392 }
393 } else {
394 Bson::Null
395 }
396 }
397 "I32Field" | "ChoiceI32Field" => {
398 if !default_value.is_null() {
399 Bson::Int32(
400 i32::try_from(default_value.as_i64().unwrap())?
401 )
402 } else {
403 Bson::Null
404 }
405 }
406 "U32Field" | "ChoiceU32Field" | "I64Field" | "ChoiceI64Field" => {
407 if !default_value.is_null() {
408 Bson::Int64(
409 default_value.as_i64().unwrap()
410 )
411 } else {
412 Bson::Null
413 }
414 }
415 "F64Field" | "ChoiceF64Field" => {
416 if !default_value.is_null() {
417 Bson::Double(
418 default_value.as_f64().unwrap()
419 )
420 } else {
421 Bson::Null
422 }
423 }
424 "BoolField" => {
425 if !default_value.is_null() {
426 Bson::Boolean(
427 default_value.as_bool().unwrap()
428 )
429 } else {
430 Bson::Boolean(false)
431 }
432 }
433 "FileField" => {
434 if !default_value.is_null() {
435 let mut file_data = serde_json::from_value::<FileData>(default_value.clone())?;
436 // Define flags to check.
437 if file_data.path.is_empty() || file_data.url.is_empty() {
438 Err(format!("Model: `{}` > Field: `{}` ; Method: \
439 `migrat()` => Check the `path` and `url` \
440 attributes in the `default` field parameter.",
441 meta.model_name, field_name)
442 )?
443 }
444 // Create path for validation of file.
445 let path: String = file_data.path.clone();
446 let f_path = Path::new(path.as_str());
447 if !f_path.is_file() {
448 Err(format!("Model: `{}` > Field: `{}` ; \
449 Method: `migrat()` => File is missing - {}",
450 meta.model_name, field_name, path)
451 )?
452 }
453 // Get file metadata.
454 let metadata = f_path.metadata()?;
455 // Get file size in bytes.
456 file_data.size = metadata.len() as f64;
457 // Get file name.
458 file_data.name = f_path.file_name().unwrap().to_str().unwrap().to_string();
459 // Create doc.
460 let result = to_document(&file_data)?;
461 Bson::Document(result)
462 } else {
463 Bson::Null
464 }
465 }
466 "ImageField" => {
467 if !default_value.is_null() {
468 let mut file_data = serde_json::from_value::<ImageData>(default_value.clone())?;
469 // Define flags to check.
470 if file_data.path.is_empty() || file_data.url.is_empty() {
471 Err(format!("Model: `{}` > Field: `{}` ; Method: \
472 `migrat()` => Check the `path` and `url` \
473 attributes in the `default` field parameter.",
474 meta.model_name, field_name
475 ))?
476 }
477 // Create path for validation of file.
478 let path: String = file_data.path.clone();
479 let f_path = Path::new(path.as_str());
480 if !f_path.is_file() {
481 Err(format!("Model: `{}` > Field: `{}` ; Method: \
482 `migrat()` => Image is missing - {}",
483 meta.model_name, field_name, path
484 ))?
485 }
486 // Get file metadata.
487 let metadata = f_path.metadata()?;
488 // Get file size in bytes.
489 file_data.size = metadata.len() as f64;
490 // Get file name.
491 file_data.name = f_path.file_name().unwrap().to_str().unwrap().to_string();
492 // Get image width and height.
493 let dimensions = image::image_dimensions(path)?;
494 file_data.width = dimensions.0 as f64;
495 file_data.height = dimensions.1 as f64;
496 // Create doc.
497 let result = to_document(&file_data)?;
498 Bson::Document(result)
499 } else {
500 Bson::Null
501 }
502 }
503 "ChoiceTextMultField" => {
504 if !default_value.is_null() {
505 let val = serde_json::from_value::<Vec<String>>(default_value.clone())?
506 .iter().map(|item| Bson::String(item.clone()))
507 .collect::<Vec<Bson>>();
508 Bson::Array(val)
509 } else {
510 Bson::Null
511 }
512 }
513 "ChoiceI32MultField" => {
514 if !default_value.is_null() {
515 let val = serde_json::from_value::<Vec<i32>>(default_value.clone())?
516 .iter().map(|item| Bson::Int32(*item))
517 .collect::<Vec<Bson>>();
518 Bson::Array(val)
519 } else {
520 Bson::Null
521 }
522 }
523 "ChoiceU32MultField" | "ChoiceI64MultField" => {
524 if !default_value.is_null() {
525 let val = serde_json::from_value::<Vec<i64>>(default_value.clone())?
526 .iter().map(|item| mongodb::bson::Bson::Int64(*item))
527 .collect::<Vec<Bson>>();
528 Bson::Array(val)
529 } else {
530 Bson::Null
531 }
532 }
533 "ChoiceF64MultField" => {
534 if !default_value.is_null() {
535 let val = serde_json::from_value::<Vec<f64>>(default_value.clone())?
536 .iter().map(|item| Bson::Double(*item))
537 .collect::<Vec<Bson>>();
538 Bson::Array(val)
539 } else {
540 Bson::Null
541 }
542 }
543 "ChoiceTextDynField" | "ChoiceTextMultDynField" | "ChoiceI32DynField"
544 | "ChoiceI32MultDynField" | "ChoiceU32DynField" | "ChoiceU32MultDynField"
545 | "ChoiceI64DynField" | "ChoiceI64MultDynField" | "ChoiceF64DynField"
546 | "ChoiceF64MultDynField" => {
547 Bson::Null
548 }
549 _ => {
550 Err(format!("Service: `{}` > Model: `{}` ; \
551 Method: `migrat()` => Invalid Field type.",
552 meta.service_name, meta.model_name
553 ))?
554 }
555 },
556 );
557 }
558 }
559 // Save updated document.
560 let query = doc! {"_id": doc_from_db.get_object_id("_id")?};
561 collection
562 .update_one(query, doc! {"$set": tmp_doc}, None)
563 .await?;
564 }
565 }
566 } else {
567 monitor_field_type_map = HashMap::new();
568 }
569
570 // Create a new database (if doesn't exist) and add new collection.
571 // -------------------------------------------------------------------------------------
572 // Get the database for the current collection of Model.
573 let db: Database = client.database(&meta.database_name);
574 // If there is no collection for the current Model, create it.
575 if !database_names.contains(&meta.database_name)
576 || !db
577 .list_collection_names(None)
578 .await?
579 .contains(&meta.collection_name)
580 {
581 db.create_collection(&meta.collection_name, None).await?;
582 }
583
584 // Get the technical database `db_green_tech` for the current model.
585 // -------------------------------------------------------------------------------------
586 let db: Database = client.database(&db_green_tech);
587
588 // Update the state of models for `models::Monitor`.
589 // -------------------------------------------------------------------------------------
590 // Check if there is a technical database of the project, if not, causes panic.
591 if !database_names.contains(&db_green_tech)
592 || !db
593 .list_collection_names(None)
594 .await?
595 .contains(&"monitor_models".to_owned())
596 {
597 Err("In the `refresh()` method, \
598 no technical database has been created for the project.")?
599 } else {
600 let collection = db.collection::<Document>("monitor_models");
601 let filter = doc! {
602 "database": &meta.database_name,
603 "collection": &meta.collection_name
604 };
605 let doc: Document = mongodb::bson::doc! {
606 "database": &meta.database_name,
607 "collection": &meta.collection_name,
608 "fields": trunc_fields_name_list.iter().map(|item| item.to_string())
609 .collect::<Vec<String>>(),
610 "field_type_map": to_bson(&trunc_field_type_map.clone())?,
611 "status": true
612 };
613 // Check if there is model state in the database.
614 if collection.count_documents(filter.clone(), None).await? == 0 {
615 // Add model state information.
616 collection.insert_one(doc, None).await?;
617 } else {
618 // Full update model state information.
619 collection
620 .update_one(filter, doc! {"$set": doc}, None)
621 .await?;
622 }
623 }
624
625 // Document management to support model fields with dynamic fields type.
626 // -------------------------------------------------------------------------------------
627 // Check if there is a technical database of the project, if not, causes panic.
628 if !database_names.contains(&db_green_tech)
629 || !db
630 .list_collection_names(None)
631 .await?
632 .contains(&"dynamic_fields".to_owned())
633 {
634 Err("In the `refresh()` method, \
635 no technical database has been created for the project.")?
636 }
637 //
638 let collection = db.collection::<Document>("dynamic_fields");
639 let filter = doc! {
640 "database": &meta.database_name,
641 "collection": &meta.collection_name
642 };
643 // Check if there is a document in the database for
644 // storing the values of dynamic fields type of model.
645 if collection.count_documents(filter.clone(), None).await? == 0 {
646 // Init new document.
647 let mut new_doc = doc! {
648 "database": &meta.database_name,
649 "collection": &meta.collection_name,
650 "fields": {}
651 };
652 // Add empty arrays to the new document.
653 let mut fields_doc = Document::new();
654 for (field_name, field_type) in field_type_map.clone() {
655 if field_type.contains("Dyn") {
656 fields_doc.insert(field_name, Bson::Array(Vec::new()));
657 }
658 }
659 // Insert new document.
660 new_doc.insert("fields".to_string(), fields_doc);
661 collection.insert_one(new_doc, None).await?;
662 } else {
663 // Get an existing document.
664 let mut exist_doc = collection.find_one(filter.clone(), None).await?.unwrap();
665 // Get a document with `dynamic_fields` fields.
666 let fields_doc = exist_doc.get_document_mut("fields")?;
667 // Get a list of fields from the technical database,
668 // from the `dynamic_fields` collection for current Model.
669 let dyn_fields_from_db: Vec<String> =
670 fields_doc.keys().map(|item| item.into()).collect();
671 // Create an empty list for fields with dynamic field types.
672 let mut dyn_fields_from_model: Vec<String> = Vec::new();
673 // Add new (if any) fields in `fields_doc`.
674 for (field_name, field_type) in trunc_field_type_map.clone() {
675 if field_type.contains("Dyn") {
676 dyn_fields_from_model.push(field_name.clone());
677 // If the new field or fields type do not match,
678 // initialize with an empty array.
679 if !dyn_fields_from_db.contains(&field_name)
680 || (field_type
681 != *monitor_field_type_map
682 .get(field_name.as_str())
683 .unwrap_or(&String::new()))
684 {
685 fields_doc.insert(field_name, Bson::Array(Vec::new()));
686 }
687 }
688 }
689 // Remove orphaned fields.
690 for field_name in dyn_fields_from_db {
691 if !dyn_fields_from_model.contains(&field_name) {
692 fields_doc.remove(&field_name).unwrap();
693 }
694 }
695 // Full update existing document.
696 collection
697 .update_one(filter, doc! {"$set":exist_doc}, None)
698 .await?;
699 }
700 }
701 // Run reorganize databases state.
702 self.napalm(client).await?;
703 //
704 Ok(())
705 }
706}