mongodb_gridfs/bucket/
find.rs

1use crate::{bucket::GridFSBucket, options::GridFSFindOptions};
2use bson::Document;
3use mongodb::error::Result;
4use mongodb::options::FindOptions;
5use mongodb::Cursor;
6
7impl GridFSBucket {
8    /**
9    Find and return the files collection documents that match @filter.
10    [Spec](https://github.com/mongodb/specifications/blob/master/source/gridfs/gridfs-spec.rst#generic-find-on-files-collection)
11
12    # Examples
13
14    ```rust
15    use bson::doc;
16    # #[cfg(feature = "async-std-runtime")]
17    # use futures::stream::StreamExt;
18    # #[cfg(any(feature = "default", feature = "tokio-runtime"))]
19    use tokio_stream::StreamExt;
20    # use mongodb::error::Result;
21    # use mongodb::Client;
22    # use mongodb::Database;
23    use mongodb_gridfs::{bucket::GridFSBucket, options::GridFSFindOptions};
24    # use mongodb_gridfs::options::GridFSBucketOptions;
25
26    # #[tokio::main]
27    # async fn main() -> Result<()> {
28    #    let client = Client::with_uri_str(
29    #        &std::env::var("MONGO_URI").unwrap_or("mongodb://localhost:27017/".to_string()),
30    #    )
31    #    .await?;
32    #    let db: Database = client.database("test");
33    #    let bucket = &GridFSBucket::new(db.clone(), Some(GridFSBucketOptions::default()));
34    let mut cursor = bucket
35            .find(doc! {"filename":"test.txt"}, GridFSFindOptions::default())
36            .await?;
37
38        while let Some(_doc) = cursor.next().await {
39            // ...
40        }
41    #    Ok(())
42    # }
43    ```
44     */
45    pub async fn find(
46        &self,
47        filter: Document,
48        options: GridFSFindOptions,
49    ) -> Result<Cursor<Document>> {
50        let dboptions = self.options.clone().unwrap_or_default();
51        let bucket_name = dboptions.bucket_name;
52        let file_collection = bucket_name + ".files";
53        let files = self.db.collection::<Document>(&file_collection);
54
55        let find_options = FindOptions::builder()
56            .allow_disk_use(options.allow_disk_use)
57            .limit(options.limit)
58            .max_time(options.max_time)
59            .no_cursor_timeout(options.no_cursor_timeout)
60            .skip(options.skip)
61            .sort(options.sort)
62            .read_concern(dboptions.read_concern)
63            .build();
64
65        files.find(filter, find_options).await
66    }
67}
68
69#[cfg(test)]
70mod tests {
71    use super::GridFSBucket;
72    use crate::{
73        options::{GridFSBucketOptions, GridFSFindOptions},
74        GridFSError,
75    };
76    use bson::doc;
77    #[cfg(feature = "async-std-runtime")]
78    use futures::stream::StreamExt;
79    use mongodb::{Client, Database};
80    #[cfg(any(feature = "default", feature = "tokio-runtime"))]
81    use tokio_stream::StreamExt;
82    use uuid::Uuid;
83
84    fn db_name_new() -> String {
85        "test_".to_owned()
86            + Uuid::new_v4()
87                .hyphenated()
88                .encode_lower(&mut Uuid::encode_buffer())
89    }
90
91    #[tokio::test]
92    async fn find_a_file() -> Result<(), GridFSError> {
93        let client = Client::with_uri_str(
94            &std::env::var("MONGO_URI").unwrap_or("mongodb://localhost:27017/".to_string()),
95        )
96        .await?;
97        let dbname = db_name_new();
98        let db: Database = client.database(&dbname);
99        let bucket = &GridFSBucket::new(db.clone(), Some(GridFSBucketOptions::default()));
100        let id = bucket
101            .clone()
102            .upload_from_stream("test.txt", "test data".as_bytes(), None)
103            .await?;
104
105        assert_eq!(id.to_hex(), id.to_hex());
106
107        let mut cursor = bucket
108            .find(doc! {"filename":"test.txt"}, GridFSFindOptions::default())
109            .await?;
110
111        while let Some(doc) = cursor.next().await {
112            let doc = doc.unwrap();
113            assert_eq!(doc.get_str("filename").unwrap(), "test.txt");
114            assert_eq!(doc.get_i32("chunkSize").unwrap(), 261120);
115            assert_eq!(doc.get_i64("length").unwrap(), 9);
116            assert_eq!(
117                doc.get_str("md5").unwrap(),
118                "eb733a00c0c9d336e65691a37ab54293"
119            );
120        }
121        db.drop(None).await?;
122        Ok(())
123    }
124
125    #[tokio::test]
126    async fn find_a_non_existing_file() -> Result<(), GridFSError> {
127        let client = Client::with_uri_str(
128            &std::env::var("MONGO_URI").unwrap_or("mongodb://localhost:27017/".to_string()),
129        )
130        .await?;
131        let dbname = db_name_new();
132        let db: Database = client.database(&dbname);
133        let bucket = &GridFSBucket::new(db.clone(), Some(GridFSBucketOptions::default()));
134        let id = bucket
135            .clone()
136            .upload_from_stream("test.txt", "test data".as_bytes(), None)
137            .await?;
138
139        assert_eq!(id.to_hex(), id.to_hex());
140
141        let mut cursor = bucket
142            .find(doc! {"filename":"null.txt"}, GridFSFindOptions::default())
143            .await?;
144
145        match cursor.next().await {
146            None => assert!(true),
147            Some(_) => assert!(false),
148        }
149
150        db.drop(None).await?;
151        Ok(())
152    }
153}