Reputation: 349
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
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
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
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