Minimal Reproducible Example
pub struct User { pub id: i32, pub name: String, pub match_id: i32, } pub struct Match { pub id: i32, pub name: String, } pub struct MatchWithUsers { pub id: i32, pub name: String, pub users: Vec<User>, } fn main() { let query_result: Vec<(Match, Option<User>)> = vec![ ( Match { id: 1, name: String::from("1st match"), }, Some(User { id: 1, name: String::from("Jack"), match_id: 1, }), ), ( Match { id: 2, name: String::from("2nd match"), }, Some(User { id: 2, name: String::from("John"), match_id: 2, }), ), ( Match { id: 3, name: String::from("3rd match"), }, None, ), ]; let mut response: Vec<MatchWithUsers> = Vec::new(); for (m, u) in &query_result { let existing_match = &response .into_iter() .find(|match_with_user| match_with_user.id == m.id); match existing_match { Some(found_match) => { println!("Inser user into match: {}", found_match.name); match u { Some(mut user) => { found_match.users.push(user); } None => println!("No users."), } } None => { println!("No existing match. Add to response."); let user = u.as_ref().unwrap(); response.push(MatchWithUsers { id: m.id, name: m.name.clone(), users: vec![], }); } } } println!("Response with: {}", response.len()); } warning: unused variable: `user` --> src/main.rs:69:21 | 69 | let user = u.as_ref().unwrap(); | ^^^^ help: consider prefixing with an underscore: `_user` | = note: `#[warn(unused_variables)]` on by default warning: variable does not need to be mutable --> src/main.rs:61:26 | 61 | Some(mut user) => { | ----^^^^ | | | help: remove this `mut` | = note: `#[warn(unused_mut)]` on by default error[E0382]: use of moved value: `response` --> src/main.rs:53:31 | 50 | let mut response: Vec<MatchWithUsers> = Vec::new(); | ------------ move occurs because `response` has type `std::vec::Vec<MatchWithUsers>`, which does not implement the `Copy` trait ... 53 | let existing_match = &response | ^^^^^^^^ value moved here, in previous iteration of loop error[E0507]: cannot move out of `u.0` which is behind a shared reference --> src/main.rs:60:23 | 60 | match u { | ^ 61 | Some(mut user) => { | -------- | | | data moved here | move occurs because `user` has type `User`, which does not implement the `Copy` trait error[E0596]: cannot borrow `found_match.users` as mutable, as it is behind a `&` reference --> src/main.rs:62:25 | 62 | found_match.users.push(user); | ^^^^^^^^^^^^^^^^^ `found_match` is a `&` reference, so the data it refers to cannot be borrowed as mutable My problem
I have an API test project using Rocket and Diesel.
The following method does a Diesel query and should map the result to a JSON response. This is a response of all matches in the database with thier users. The users should be nested in each Match node.
My solution attempt
- I create a vector.
- Iterate in the query result;
- Check if the match already exists in my vector, if it does, add the user info (coming from the query result) and add it to the users attribute in the current
MatchWithUser, otherwise just add a struct (MatchWithUsers) to the vector.
pub fn show_all_matches2() -> Vec<MatchWithUsers> { use schema::*; let connection = establish_connection(); let query_result: Vec<(Match, Option<User>)> = matches::table .left_join(users::table.on(users::match_id.eq(matches::id))) .load(&connection) .expect("Error loading matches"); let mut response: Vec<MatchWithUsers> = Vec::new(); for (m, u) in &query_result { let existing_match = &response .into_iter() .find(|match_with_user| match_with_user.id == m.id); match existing_match { Some(mut found_match) => { println!("Inser user into match: {}", found_match.name); found_match.users.push(u.unwrap()); } None => { println!("No existing match. Add to response."); let user = u.as_ref().unwrap(); response.push(MatchWithUsers { id: m.id, name: m.name.clone(), players_count: m.players_count, users: vec![User { id: user.id, name: user.name.clone(), match_id: user.match_id, }], }); } } } response } Structs
use crate::schema::{matches, users}; use serde::{Deserialize, Serialize}; #[derive(Queryable, Identifiable, Associations, Serialize, Deserialize)] #[belongs_to(Match)] #[table_name = "users"] pub struct User { pub id: i32, pub name: String, pub match_id: i32, } #[derive(Queryable, Identifiable, Serialize, Deserialize)] #[table_name = "matches"] pub struct Match { pub id: i32, pub name: String, pub players_count: i32, } #[derive(Serialize, Deserialize)] pub struct MatchWithUsers { pub id: i32, pub name: String, pub players_count: i32, pub users: Vec<User>, } Errors

$ cargo run Compiling got_board_api_v3 v0.1.0 (/Users/tauil/Projects/got/got-board-api-v3) error[E0382]: use of moved value: `response` --> src/lib.rs:54:31 | 51 | let mut response: Vec<MatchWithUsers> = Vec::new(); | ------------ move occurs because `response` has type `std::vec::Vec<models::MatchWithUsers>`, which does not implement the `Copy` trait ... 54 | let existing_match = &response | ^^^^^^^^ value moved here, in previous iteration of loop error[E0507]: cannot move out of `existing_match.0` which is behind a shared reference --> src/lib.rs:58:15 | 58 | match existing_match { | ^^^^^^^^^^^^^^ 59 | Some(mut found_match) => { | --------------- | | | data moved here | move occurs because `found_match` has type `models::MatchWithUsers`, which does not implement the `Copy` trait error[E0507]: cannot move out of `*u` which is behind a shared reference --> src/lib.rs:61:40 | 61 | found_match.users.push(u.unwrap()); | ^ | | | move occurs because `*u` has type `std::option::Option<models::User>`, which does not implement the `Copy` trait | help: consider borrowing the `Option`'s content: `u.as_ref()` Query result in the Postgres client:
select * from matches left join users on matches.id = users.match_id; id | name | players_count | id | name | match_id ----+---------------------+---------------+----+-----------+---------- 1 | My first match | 3 | 1 | Rafael | 1 1 | My first match | 3 | 2 | Leandro | 1 1 | My first match | 3 | 3 | Vagner | 1 2 | Just a second match | 4 | 4 | Vagner | 2 2 | Just a second match | 4 | 5 | Leandro | 2 2 | Just a second match | 4 | 6 | Rafael | 2 2 | Just a second match | 4 | 7 | Wanderson | 2 3 | Amazing match | 6 | | | (8 rows)
Vec, you should consider using aHashMap<i32, MatchWithUsers>, which would be much more efficient when looking for duplicates, then use theEntryAPI to insert or modify the stored value.