Home > OS >  NextJS / MongoDB - assign data from one collection into another
NextJS / MongoDB - assign data from one collection into another

Time:10-23

I know this question got asked very often but I try to solve it with react-hook-form and a custom selector tool so I didn`t found that case. The main goal is to assign data from employees collection to company collection. My models are looking like this (shorted):

const companySchema = new mongoose.Schema(
  {
    name: {
      type: String,
      required: true,
    },
    employees: [
      {
        type: mongoose.Schema.Types.ObjectId,
        ref: 'Employee',
      },
    ],  
  }
);
const employeeSchema = new mongoose.Schema(
  {
    firstName: {
      type: String,
      required: true,
    },
    lastName: {
      type: String,
      required: true,
    },
  }
);

My create page is looking like this:

export default function CreateSet() {
  const { register, handleSubmit } = useForm();
  const router = useRouter();
  const { redirect } = router.query;
  const { state, dispatch } = useContext(Store);
  const { vendorInfo } = state;
  useEffect(() => {
    if (!vendorInfo) {
      router.push('/');
    }
  }, []);

  const submitHandler = async ({
    name,
    employees: [],
    },
  }) => {
    try {
      const { data } = await axios.post(
        '/api/company/',
        {
          name,
          employees: [],
        },
        {
          headers: { authorization: `Bearer ${vendorInfo.token}` },
        }
      );
      dispatch({ type: 'COMPANY_CREATE', payload: data });
      router.push(redirect || '/vendor/');
    } catch (err) {
      console.log(getError(err));
    }
  };
  return (
    <div title='CompanyCreation' className={styles.register_container}>
      <form onSubmit={handleSubmit(submitHandler)}>
        <h1>Create Company</h1>
        <ul>
          <li>
            <input
              id='name'
              label='name'
              placeholder='Name'
              {...register('name', { required: true })}
            />
          </li>
          <li>
            <p>Employees:</p>
            <EmployeeSelector employees={employees} />
          </li>
          <li>
            <button type='submit'>Create</button>
          </li>
        </ul>
      </form>
    </div>
  );
}

Here is the EmployeeSelector component:

import React, { useEffect, useReducer, useContext, useState } from 'react';
import axios from 'axios';
import Table from 'react-bootstrap/Table';
import dynamic from 'next/dynamic';
import { useRouter } from 'next/router';
import { getError } from '../utils/error';
import { Store } from '../utils/store';

function reducer(state, action) {
  switch (action.type) {
    case 'FETCH_REQUEST':
      return { ...state, loading: true, error: '' };
    case 'FETCH_SUCCESS':
      return { ...state, loading: false, employees: action.payload, error: '' };
    case 'FETCH_FAIL':
      return { ...state, loading: false, error: action.payload };

    default:
      state;
  }
}

function EmployeeList() {
  const { state } = useContext(Store);
  const router = useRouter();
  const { vendorInfo } = state;
  const [employee, setEmployee] = useState([]);

  const [{ loading, error, products }, dispatch] = useReducer(reducer, {
    loading: true,
    employees: [],
    error: '',
  });

  //selected employees
  const selectHandler = (e) => {
    e.preventDefault;
    e.target.value .....????

};

  useEffect(() => {
    const fetchData = async () => {
      try {
        dispatch({ type: 'FETCH_REQUEST' });
        const { data } = await axios.get(`/api/employee`, {
          headers: { authorization: `Bearer ${vendorInfo.token}` },
        });
        dispatch({ type: 'FETCH_SUCCESS', payload: data });
      } catch (err) {
        dispatch({ type: 'FETCH_FAIL', payload: getError(err) });
      }
    };

    fetchData();
  }, []);

  return (
    <div title='EmployeeList'>
      {loading ? (
        <p>Loading</p>
      ) : error ? (
        <p>{error}</p>
      ) : (
        <Table striped bordered>
          <thead>
            <tr>
              <th>Select</th>
              <th>First name</th>
              <th>Last name</th>
            </tr>
          </thead>
          <tbody>
            {employees.map((employee) => (
              <tr key={employee._id}>
                <td>
                  <input
                    id='employees'
                    label='employees'
                    type: checkbox
                    {...register('employees', { required: true })}
                    onClick={selectHandler}
                  />
                </td>
                <td>{employee.firstName}</td>
                <td>{employee.lastName}</td>
              </tr>
            ))}
          </tbody>
        </Table>
      )}
    </div>
  );
}

export default dynamic(() => Promise.resolve(EmployeeList), { ssr: false });

So what I try to achieve is to give the user the posibility to select one or multiple employees from list and assign them to the company. Im realy not sure how to make it - my thought was to overgive the values into the state of EmployeeSelector and from there fetch these and fire them into the companys collection. Maybe this is the wrong way, anyway I dont know how to achieve this strategy so the selectorHandler looks like it does. Would someone help me out by telling me the right way to handle that case ? Thank you people!

CodePudding user response:

To assign data from one collection to another you need to create an API endpoint (nodejs) - imagine you have created /api/getComplexData.js file

With this endpoint, you can write complex "queries" to get any data from any collection. All database operations you make at API endpoint. Take a look at the nextjs/mongodb examples (one, two)

Take a look at the complex examples, for example, at $lookup. Do not overwrite data at the front end. You can "merge", "modify" and delete any type of data with mongodb queries

  • Related