Mongodb insert_many with array instead of vector

This works:

    let documents = vec![
        doc! {"name": "Maisey", "breed": "Treeing Walker Coonhound"},
        doc! {"name": "Ramsay", "breed": "Native American Indian Dog"},
        doc! {"name": "Comet", "breed": "Whippet"},
    ];
    coll.insert_many(documents, None).await?;

This does not. Is there a way to get insert_many to work with an array instead of a vector?

    let documents: [Document; 3] = [
        doc! {"name": "Maisey", "breed": "Treeing Walker Coonhound"},
        doc! {"name": "Ramsay", "breed": "Native American Indian Dog"},
        doc! {"name": "Comet", "breed": "Whippet"},
    ];
    coll.insert_many(&documents, None).await?;

The error is:
type mismatch resolving <&[mongodb::bson::Document; 3] as IntoIterator>::Item == mongodb::bson::Document
I know that the array type does implement IntoIterator so I thought this would work.

It does not, for now. It's slice, i.e. &[T], which implements IntoIterator, but, since this is the reference and not an owned container, iterator over it can yield only &Ts, not Ts, which insert_many requests.

1 Like

Is there any way to make this work with an array or do I really have to put the documents into a vector?

I must not understand how to read the Rust documentation correctly. I looked here: array - Rust. It says:

Arrays of any size implement the following traits if the element type allows it:

How should I have inferred from that that it isn't arrays that implement IntoIterator, but only slices of arrays. Doesn't the syntax &[T; N] indicate a reference to an array?

The point is that [T; N] without the ampersand does not implement IntoIterator.

1 Like

Doesn't &[T; N] just mean a reference to an array?
I tried passing a reference to my array, but it still says:

type mismatch resolving <&[mongodb::bson::Document; 3] as IntoIterator>::Item == mongodb::bson::Document"

It seems like the issue is that it doesn't know that the type of the items in the array is mongodb::bson::Document, but I did specify that in the type of the array.

Am I trying to do something that just is not possible or is there a way to get this to work with an array reference?

You're right that &[T; N] implements IntoIterator, but there's one small detail we should pay attention to – &[T; N]'s IntoIterator impl has Type = &T, which is &bson::Document, but your insert_many expects IntoIterator<Type = bson::Document> – with no reference.

So that's a known limitation of arrays, but there are a few workarounds to get a Item=T iterator from an array:

  • […].iter().cloned()
  • on nightly: std::array::IntoIter::new([…])
  • using array of Options: [Some(…), Some(…), …].iter_mut().map(Option::take).map(Option::unwrap)
4 Likes

Thinking about this, I'd actually open an issue about insert_many requiring owned documents. That shouldn't be the case – it doesn't need ownership of the documents, because MongoDB runs in a separate server process, and documents are transferred between client and server by serializing them into a binary format and sending a bunch of bytes through a TCP socket. So moving ownership shouldn't be necessary, and the current API design seems overly demanding.

3 Likes

I tried your first suggestion of using documents.iter().cloned() and it worked!
I don't really have a reason to not take the easy path and just use a vector.
I just wanted to understand if it is was possible to use an array instead.