Why batchWrite only write up to 3 data? Firestore - javascript

I am using Firestore to store data for my Reactjs app. I have a function as such:
export async function batchAddProduct(data) {
const productRef = doc(collection(db, "product"));
const batch = writeBatch(db);
for (const datum of data) {
batch.set(productRef, datum);
}
return await batch
.commit()
.then(() => {
return { data: true, error: null };
})
.catch((err) => {
return { data: null, error: err };
});
}
So basically, I want to add lots of data at once. Hence, I'm using the writeBatch method. I see from an answer in SO where they use doc(collection(db, "product") to generate an empty doc first then use batch.set() to fill the doc. So I'm doing that here, and I'm passing up to 500 data at once (which is the maximum limit of a batch write), but somehow only up to 3 data is being written into the database. Why is that? Am I missing something?
Update:
According to the comment:
When I console.log(data), it basically prints out an array with 500 objects in it (which I definitely can't paste in here). But I can assure you that it is receiving the correct data.
batchAddProduct is called in a redux sagas as such:
function* BATCH_ADD_PRODUCT(input) {
yield put({
type: actions.SET_STATE,
payload: {
loadingUpdate: true,
},
});
const { data, error } = yield call(batchAddProduct, input.payload.data);
if (data) {
yield put({
type: actions.GET_PRODUK,
});
yield put({
type: actions.SET_STATE,
payload: {
loadingUpdate: false,
alert: {
type: "success",
message: "Product is added successfully.",
},
},
});
}
if (error) {
console.log(error);
yield put({
type: actions.SET_STATE,
payload: {
loadingUpdate: false,
alert: {
type: "error",
message: error.message || "Error occured.",
},
},
});
}
}
and I use this in a dispatch as such:
dispatch({
type: actions.BATCH_ADD_PRODUK,
payload: {
data: data, // WHICH CONTAINS UP TO 500 OBJECTS
},
});

I haven't tried the generator function with a batched write yet but try the following:
const myArray: any = []
const batches: WriteBatch[] = []
myArray.forEach((doc, i) => {
if (i % 500 === 0) {
batches.push(writeBatch(db))
}
const productRef = doc(collection(db, 'colName'))
const batch = batches[batches.length - 1]
batch.set(productRef, { ...data })
})
await Promise.all(batches.map((batch) => batch.commit()))
console.log('done')

Related

GET and POST request in AXIOS

i try to post the values to the mongo server and get the values from server with same route.it is working but each and every time i need to reload the page manualy. is it right to do the POST and GET request in same route.
i try to make single page application
const createJob = async () => {
dispatch({ type: CREATE_LIST_BEGIN })
try {
const { item, price, stock } = state
await axios.post('/api/v1/list', { item, price, stock })
dispatch({ type: CREATE_LIST_SUCCESS })
dispatch({ type: CLEAR_VALUES })
} catch (error) {
if (error.response.status === 401) return
dispatch({ type: CREATE_LIST_ERROR, payload: { msg: error.response.data.msg } })
}
clearAlert()
}
const getItems = async () => {
dispatch({ type: GET_LIST_BEGIN })
try {
const { data } = await axios.get('/api/v1/list')
const { items } = data
dispatch({ type: GET_LIST_SUCCESS, payload: { items } })
} catch (error) {
console.log(error.response)
}
}
useEffect(() => {
getItems()
}, [])
The POST handler in your API should return the newly added record and createJob() should add the record to your store. So it would look something like this:
const createJob = async () => {
dispatch({ type: CREATE_LIST_BEGIN })
try {
const { item, price, stock } = state
// get the new item returned from API
const {data} = await axios.post('/api/v1/list', { item, price, stock })
// dispatch an action creator which adds the new item
dispatch({ type: ADD_LIST_ITEM, payload: { item: data.item } })
dispatch({ type: CREATE_LIST_SUCCESS })
dispatch({ type: CLEAR_VALUES })
} catch (error) {
if (error.response.status === 401) return
dispatch({ type: CREATE_LIST_ERROR, payload: { msg: error.response.data.msg } })
}
clearAlert()
}

React Jest tests failing with MSW

I have created a basic React application and configured MSW following the instructions to setup for unit tests (node environment) and browser
The App component uses a custom hook useFormSubmission and renders a simple form with a username text field and a submit button. The form's submit handler uses the callback returned by the custom hook.
All the unit tests are failing at the moment. I can see MSW receiving the requests but I don't see any response coming back. The console logs the reducer state Status: pending but it does not go beyond that (seems like the response is swallowed/lost?) Strangely enough, the app works when running with development server npm start.
const useFormSubmissionReducer = (state, action) => {
switch (action.type) {
case "start":
return { status: "pending" };
case "resolved":
return { status: "resolved", data: action.data };
case "rejected":
return { status: "rejected", error: action.error };
default:
throw new Error(`Unsupported type: ${action.type}`);
}
};
const handleResponse = async (response) => {
const data = await response.json();
if (response.status >= 200 && response.status <= 299) {
return Promise.resolve(data);
} else {
return Promise.reject(data);
}
};
const useFormSubmission = () => {
const [state, dispatch] = useReducer(useFormSubmissionReducer, {
status: "idle",
data: null,
error: null,
});
const callback = useCallback((request) => {
const payload = JSON.stringify(request);
console.log("Dispatching: ", request);
dispatch({ type: "start" });
fetch("/api/register", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: payload,
})
.then(handleResponse)
.then(
(data) => {
console.log("Data: ", data);
dispatch({ type: "resolved", data });
},
(error) => {
console.log("Error: ", error);
dispatch({ type: "rejected", error });
}
)
.catch((error) => {
console.log("Exception: ", error);
dispatch({ type: "rejected", error: { message: error.message } });
});
}, []);
return [state, callback];
};
I have spent 3 days digging around and trying to figure out if something is wrong in the config or the way the custom hook or the component is written.
Turns out the tests were executing pretty fast ending up with race condition(s). I've added await waitForElementToBeRemoved(screen.getByText(<element you are looking for>)) and all tests are passing now.

How to create complex nested documents using mongoose?

I want to create a complex nested document which can store values like this
category: {
"fish": ["Sardines", "Goldfish"],
"dogs": ["German Shepherd", "Dobberman"]
}
Here's what I tried
export const CategorySchema = new mongoose.Schema(
{
category: {
type: Map,
of: [String],
},
},
{ timestamps: true }
);
I passed data like this (from console)
this is how the passed data looks like
Nothing is being created in the database. Also no error.
export default async (req, res) => {
const { method } = req;
switch (method) {
case "GET":
try {
const categories = await Category.find({});
res.json({ success: true, data: categories });
} catch (error) {
res.json({ success: false });
}
break;
case "POST":
try {
let data = req.body;
data = JSON.parse(data);
const category = new Category(data);
const doc = await category.save();
console.log("Doc from Categories API", doc);
res.json({ success: true, data: doc });
} catch (error) {
res.json({ success: false });
}
break;
default:
res.status(400).json({ success: false });
break;
}
};
Can anyone advise me, please?

componentwillmount() Uncaught Error: Actions must be plain objects. Use custom middleware for async actions

I'm implementing get all image by type with redux-saga. I have 2 types, let's say, type kristik and type motif.
When I'm implementing type kristik, it got successful response, but when it comes to type motif, the response is error.
here my code that has the error in console
componentWillMount() => {
const { dispatch } = this.props;
dispatch(getAllMotif());
}
I got error in dispatch(getAllMotif()); in commponentWillMount()
Here my getAllMotif() code
getAllMotif(token) {
const path = `motif`;
const method = 'get';
return request.process(method, path, null, token);
},
Here my sagas getAllMotif code
export function* getAllMotif() {
try {
let { detail } = yield select(state => state.user);
const result = yield call(API.getAllMotif, detail.api_token);
yield put({
type: types.GET_ALL_MOTIF_SUCCESS,
payload: result,
});
} catch (err) {
yield put(handleError(err));
yield put({
type: types.GET_ALL_MOTIF_FAILURE,
payload: err,
});
}
}
here my reducer
case types.GET_ALL_MOTIF_SUCCESS:
return {
...state,
motif: [
...action.payload.data.data
]
};
here my request code
internals.process = (method, path, payload, token, contentType=internals.contentType) => {
const request = {
url: `${API_URL}/${path}`,
method: method,
headers: {
'Content-Type': contentType,
'Accept': 'application/json',
},
};
if (token) {
request.params = {
token: token,
};
}
if (payload) {
request.data = payload;
}
return axios.request(request)
.then(res => {
if (![200, 201].includes(res.status)) {
throw new Error(res.status);
}
return res.data;
})
.catch((error) => {
console.error(method, path, error);
return Promise.reject({
message: error.response.data.error,
code: error.response.status
});
});
};
I don't know why in this type get error, because in type kristik also have very similar code.
You didn't dispatch an action that wasn't a plain object, your function getAllMotif not return a plain object. That lead to the error here.
You should dispatch an normal action
getAllMotifAction(token) {
const path = `motif`;
const method = 'get';
return { type: 'GET_ALL_MOTIF', data: { path, method } };
},
Then in in saga, you catch this action and handle it with your saga function
takeLatest('GET_ALL_MOTIF', getAllMotif);

Why is React generator function with Yield not waiting?

In a React app, I do not understand why the Yield line in a generator function is not 'waiting'? Specifically, in the LOGIN function below, I would expect the Yield line immediately following console.log("Step 3") to pause until it was completed; however it does NOT pause and Step 8 is immediately processed. I would expect the STEPS in the console.log to follow the logical numerical order. The actual order that is printed out in the browser console window is: 1,2,3,8,9,10,4,5,6,7. Can someone explain why it is NOT pausing?
export function* LOGIN({ payload }) {
const { email, password } = payload
yield put({
type: 'user/SET_STATE',
payload: {
loading: true,
},
})
let userCog
try {
console.log("Step 1")
userCog = yield call(login, email, password)
console.log("Step 2")
} catch (err) {
if (err.code === 'UserNotConfirmedException') {
yield put({
type: 'user/SET_STATE',
payload: {
loading: true,
email,
},
})
yield history.push('/system/verification')
}
}
console.log("Step 3")
yield put({
type: 'user/LOAD_CURRENT_ACCOUNT',
})
console.log("Step 8")
if (userCog) {
console.log("Step 9")
yield history.push('/dashboard/analytics')
console.log("Step 10")
}
}
export function* LOAD_CURRENT_ACCOUNT() {
yield put({
type: 'user/SET_STATE',
payload: {
loading: true,
},
})
console.log("Step 4")
const response = yield call(currentUser)
console.log("Step 5")
if (response) {
const { username } = response
yield put({
type: 'user/SET_STATE',
payload: {
id: '123',
name: 'Administrator',
email: username,
role: 'admin',
authorized: true,
},
})
}
console.log("Step 6")
yield put({
type: 'user/SET_STATE',
payload: {
loading: false,
},
})
console.log("Step 7")
}
EDIT: Here is the redux dispatch from the Login UI Component
onSubmit = event => {
event.preventDefault()
const { form, dispatch } = this.props
form.validateFields((error, values) => {
if (!error) {
dispatch({
type: 'user/LOGIN',
payload: values,
})
}
})
}

Categories

Resources