Reputation: 1076
I want to create line chart with chart.js and it needs data with an array.
And I want to create a chart of post views by date. The range was set based on one week, and counters collection was created in MongoDB.
One week is 7 days so I use for loop to query seven times and get each counter value. The results are fine. And there is no problem with frontEnd side but sometime server send wrong data.
DB Data
{
"_id": {
"$oid": "5f91359ee04cf21abc1920d8"
},
"repoName": "NodeJSK",
"repoNumber": 96127950,
"userName": "writingdeveloper",
"userNumber": 6832586,
"viewDate": "2020-10-22",
"__v": 0,
"count": 2
},
{
"_id": {
"$oid": "5f9135a8e04cf21abc1920da"
},
"repoName": "Projects",
"repoNumber": 98097935,
"userName": "writingdeveloper",
"userNumber": 6832586,
"viewDate": "2020-10-22",
"__v": 0,
"count": 2
},
{
"_id": {
"$oid": "5f9135aae04cf21abc1920db"
},
"repoName": "Udacity-Front-End-Web-Developer-Nanodegree",
"repoNumber": 100840518,
"userName": "writingdeveloper",
"userNumber": 6832586,
"viewDate": "2020-10-21",
"__v": 0,
"count": 2
},
{
"_id": {
"$oid": "5f9135ace04cf21abc1920dc"
},
"repoName": "HYCU-Department-of-Computer-Engineering",
"repoNumber": 101602788,
"userName": "writingdeveloper",
"userNumber": 6832586,
"viewDate": "2020-10-20",
"__v": 0,
"count": 2
},
{
"_id": {
"$oid": "5f9135afe04cf21abc1920dd"
},
"repoName": "ZzapCord",
"repoNumber": 108807703,
"userName": "writingdeveloper",
"userNumber": 6832586,
"viewDate": "2020-10-19",
"__v": 0,
"count": 3
},
{
"_id": {
"$oid": "5f9135bfe04cf21abc1920e2"
},
"repoName": "Scrimba-React-Chat-App",
"repoNumber": 141670388,
"userName": "writingdeveloper",
"userNumber": 6832586,
"viewDate": "2020-10-18",
"__v": 0,
"count": 1
}
I set the viewDate data to String.
DB Schema
const counterSchema = new Schema({
count : Number,
userName: String,
userNumber: Number,
repoName: String,
repoNumber: Number,
type: Number,
viewDate: {
type: String,
default: Date.now()
}
});
Server Side Code
router.get(`/:userId/admin/getchartdata`, (req, res, next) => {
let userId = req.params.userId;
let chartArray = [];
let chartData = [];
for (let i = 0; i < 7; i++) {
let d = new Date();
d.setDate(d.getDate() - i);
chartArray.push(d.toISOString().substr(0, 10).replace('T', ''));
// console.log(chartArray[i])
Counter.aggregate([{
$match: {
userName: userId,
// userNumber: userNumber,
viewDate: chartArray[i],
}
},
{
$group: {
_id: null,
count: {
$sum: "$count"
}
}
}
], (err, viewData) => {
if (err) throw err;
if (viewData.length === 0) { // When date count value is [] push 0 value.
viewData = 0;
} else {
viewData = viewData[0].count
}
chartData.push(viewData)
console.log(chartData)
})
}
})
What I expected
[4,2,2,3,1,0,0] // Seven days count's
But When I refresh page several times, Sometimes, server send a wrong array. like this data
[ 2 ]
[ 2, 1 ]
[ 2, 1, 2 ]
[ 2, 1, 2, 4 ]
[ 2, 1, 2, 4, 3 ]
[ 2, 1, 2, 4, 3, 0 ]
[
2, 1, 2, 4,
3, 0, 0
]
GET /favicon.ico 200 2.355 ms - 107781
GET /writingdeveloper/admin/mypage 200 358.972 ms - 28439
Session User Check : writingdeveloper
GET /writingdeveloper/admin/mypage 200 233.784 ms - 28439
GET /writingdeveloper/admin/getchartdata - - ms - -
GET /stylesheets/mypage/mypage.css 304 1.115 ms - -
GET /javascripts/mypage/mypage.js 304 0.615 ms - -
GET /javascripts/mypage/chart.js 304 1.493 ms - -
GET /images/app/Project.png 304 18.291 ms - -
Session User Check : writingdeveloper
[ 2 ]
[ 2, 3 ]
[ 2, 3, 1 ]
[ 2, 3, 1, 4 ]
[ 2, 3, 1, 4, 2 ]
[ 2, 3, 1, 4, 2, 0 ]
[
2, 3, 1, 4,
2, 0, 0
]
I don't know why this is happen. But I think the error is from using for loop so that queries are too fast so it sends wrong data.
It there anyway not to use for loop? or make it to one query. I think in one request's and seven queries are the waste of server resources and there could be errors here.
Upvotes: 0
Views: 66
Reputation: 2184
I guess that's because you're running an asynchronous block of code inside a for loop
try using async/await
to force the for loop to wait until the asynchronous block of code executes and resolves its result before getting into the next iteration
so you code may look something like
router.get(`/:userId/admin/getchartdata`, async (req, res, next) => { // using async keyword here in the function that encloses the for loop
try {
// use try catch in async/await
let userId = req.params.userId;
let chartArray = [];
let chartData = [];
for (let i = 0; i < 7; i++) {
let d = new Date();
d.setDate(d.getDate() - i);
chartArray.push(d.toISOString().substr(0, 10).replace('T', ''));
// console.log(chartArray[i])
// and using await here
// assign the result of aggregation to some variable
let viewData = Counter.aggregate([
{
$match: {
userName: userId,
// userNumber: userNumber,
viewDate: chartArray[i],
}
},
{
$group: {
_id: null,
count: {
$sum: "$count"
}
}
}
]);
if (viewData.length === 0) { // When date count value is [] push 0 value.
viewData = 0;
} else {
viewData = viewData[0].count
}
chartData.push(viewData);
console.log(chartData); // here you're logging the array after each query
}
console.log('After all the queries: ', chartData); // here we log the array after all the queries
} catch (e) {
// throw an error
throw e;
}
});
Upvotes: 1