nsog8sm43x
nsog8sm43x

Reputation: 349

How to retrieve the last added record from the database in the MERN technology stack?

I am creating an apllication using the technology stack MERN and Redux. I am wondering how to retrieve the last added record to the database using moongose. Assume it will be, for example, a list of orders assigned to a particular user.

I already have a query done on the backend that retrieves all records. It looks like this:

const getMyOrders = asyncHandler(async (req, res) => {
  const orders = await Order.find({ user: req.user._id })
  res.json(orders)
})

On the frontend, the order list is provided by the redux action:

export const listMyOrders = () => async (dispatch, getState) => {
  try {
    dispatch({
      type: ORDER_LIST_REQUEST,
    })

    const {
      userLogin: { userInfo },
    } = getState()

    const config = {
      headers: {
        Authorization: `Bearer ${userInfo.token}`,
      },
    }

    const { data } = await axios.get(`/api/orders/myorders`, config)

    dispatch({
      type: ORDER_LIST_SUCCESS,
      payload: data,
    })
  } catch (error) {
    const message =
      error.response && error.response.data.message
        ? error.response.data.message
        : error.message
    dispatch({
      type: ORDER_LIST_FAIL,
      payload: message,
    })
  }
}

and finally displayed in the reacta component:

const ProfileScreen = ({ history }) => {
  const dispatch = useDispatch()

  const userDetails = useSelector((state) => state.userDetails)
  const { loading, error, user } = userDetails

  const userLogin = useSelector((state) => state.userLogin)
  const { userInfo } = userLogin

  const orderList = useSelector((state) => state.orderList)
  const { loading: loadingOrders, error: errorOrders, orders } = orderList

  useEffect(() => {
    if (!user || !user.name) {
      dispatch(getUserDetails('profile'))
      dispatch(listMyOrders())
    }
  }, [dispatch, user])

  return (
    <tbody>
      {orders.map((order) => (
        <tr key={order._id}>
          [...]
        </tr>
      ))}
    </tbody>
  )
}

What I was able to do on my own as a partial solution to the problem is to make a separate query to the API that separately retrieves the most recently added record from the database. However, this is not a fully satisfactory solution for me, because it duplicates some of the code I've already written. Now my question is if I can do it in some other way so that it can deliver the last order to another react component ?

const getLastOrder = asyncHandler(async (req, res) => {
  const lastOrder = await Order.findOne({})
    .sort({ orderDate: -1 })
    .limit(1)
    .populate('user', 'name email')
  res.json(lastOrder)
})
export const getMyLastOrder = () => async (dispatch, getState) => {
  try {
    dispatch({
      type: ORDER_LAST_REQUEST,
    })

    const {
      userLogin: { userInfo },
    } = getState()

    const config = {
      headers: {
        Authorization: `Bearer ${userInfo.token}`,
      },
    }

    const { data } = await axios.get(`/api/orders/myorders/last`, config)

    dispatch({
      type: ORDER_LAST_SUCCESS,
      payload: data,
    })
  } catch (error) {
    const message =
      error.response && error.response.data.message
        ? error.response.data.message
        : error.message
    dispatch({
      type: ORDER_LAST_FAIL,
      payload: message,
    })
  }
}
const SecondComponent = () => {
  const dispatch = useDispatch()

  const userDetails = useSelector((state) => state.userDetails)
  const { loading, error, user } = userDetails

  const userLogin = useSelector((state) => state.userLogin)
  const { userInfo } = userLogin

  const orderLast = useSelector((state) => state.orderLast)
  const { order } = orderLast

  useEffect(() => {
    if (!user || !user.name) {
      dispatch(getUserDetails('profile'))
      dispatch(getMyLastOrder())
    }
  }, [dispatch, user])

  console.log(orderLast)
  return (
    <section>
     <p>{order._id}</p>
      [...]
    </section>

I would greatly appreciate any advice or help.

Upvotes: 5

Views: 403

Answers (3)

Ankit Gupta
Ankit Gupta

Reputation: 175

Updating your query on the backend should fix it.

Try this:

const getLastOrder = asyncHandler(async (req, res) => {
    const lastOrder = await Order.findOne({})
    .sort({ _id: -1 })
  res.json(lastOrder)
})

All documents in mongoDb are created with the _id which contains the timestamp of insertion. Hence sorting using _id : -1 would get you the latest document available. Also, findOne will already get you a single document, hence there is no need to add limit to it.

Upvotes: 1

Giant Brain
Giant Brain

Reputation: 124

You said that "this is not a fully satisfactory solution for me". So I think, you can change "react-action" part. I mean, on client side you catch the last '_id' of whole data from api. You don't have to do what you hate. I don't know structure of your code and your api, so understand following code if it has some wrong.

export const getMyLastOrder = () => async (dispatch, getState) => {
try {
  // I will omit the unnecessary parts.
  // ...

    const { data } = await axios.get(`/api/orders/myorders`, config);
    
    let max = 0;    
    for(let i = 0; i < data.length; i++){
        let id2Number = Number('0x' + data[i]._id);
        if(id2Number > max){
        max = id2Number;
      }
    }
        
    data = max;
    dispatch({
      //...
      payload: data,
    })
  } catch (error) {
    // ...
  }
}

Upvotes: 0

Arvind Pal
Arvind Pal

Reputation: 521

The last document added to the collection can be retrieved using findOne and sort _id -1

await <Model>.findOne().sort({_id:-1})

In your case, you can use the following

 const orders = await Order.findOne({ user: req.user._id }).sort({_id:-1})

Upvotes: 1

Related Questions