Redux push to 2nd level object with array - redux

So i have a redux store that looks like this:
posts : {
posts: [
0: { },
1: { }
]
}
I want to concat the array with extra items like this:
case LOAD_MORE_POSTS_SUCCESS:
return {
...state,
posts: [...state.posts, action.posts],
isFetching: false,
}
However this is pushing the extra posts only into the first level, ive tried doing something like this (no luck):
case LOAD_MORE_POSTS_SUCCESS:
return {
...state,
posts: [...state.posts.posts, action.posts],
isFetching: false,
}

Have you tried something like:
case LOAD_MORE_POSTS_SUCCESS:
return {
...state,
posts: {
posts: [...state.posts.posts, action.posts]
},
isFetching: false,
}
And if action.posts is an array (the plural form hints that it is), consider using:
posts: {
posts: [...state.posts.posts, ...action.posts]
}

Thanks to #Gila Artzi - My final code looked like this:
case LOAD_MORE_POSTS_SUCCESS:
return {
...state,
posts: [...state.posts, ...action.posts],
isFetching: false,
}

Related

What is the way to update or insert a record on Firebase with Flutter?

I have a collection users like this:
[{
'uid' : '1',
'favourites' : [
{ // fav1 },
{ // fav2 },
{ // fav3 },
etc
]
},
{
'uid' : '2',
'favourites' : [
{ // fav1 },
{ // fav2 },
{ // fav3 },
etc
]
},
etc
]
In some situations I have to update the favourites collection with a new "fav" and I can do that in this way:
final doc = FirebaseFirestore.instance.collection('users').doc(userId);
doc.update({ 'favourites': FieldValue.arrayUnion([fav.toJson()]) });
however the item might be not there so I have to use doc.set to create a new item. As I am new with Firebase, what is a "best practice" for a problem like this (if the element is not there create it first, otherwise update it)?
You can specify a merge option to set, which does precisely what you want:
doc.set({ 'favourites': FieldValue.arrayUnion([fav.toJson()]) }, SetOptions(merge : true))
You can use a function that can check if there is a doc or not with that specific info. And you can create a if-else statement depends on if there is a doc named like that or not.
An example function for checking the doc:
Future<bool> checkIfDocExists(String stuffID) async {
try {
/// Check If Document Exists
// Get reference to Firestore collection
var collectionRef = FirebaseFirestore.instance
.collection('favorites');
var doc = await collectionRef.doc(userId).get();
return doc.exists;
} catch (e) {
throw e;
}
}

How to Publish joined Data from Array of IDs in Meteor

I just want to Publish the relational Data for a Publication to client, but the issue is my Relational Data field is array of ID's of a Different Collection, I tried Different Packages but all works with single Relational ID but not working with Array of relational ID's, let assume I have two Collection Companies and Meteor.users below is my Company Document Looks like
{
_id : "dYo4tqpZms9j8aG4C"
owner : "yjzakAgYWejmJcuHz"
name : "Labbaik Waters"
peoples : ["yjzakAgYWejmJcuHz", "yjzakAgYWejmJcuHz"],
createdAt: "2019-09-18T15:33:29.952+00:00"
}
here you can see peoples field contains the user ID's as Array, so How I publish this userId's as user Documents, as for example I tried the most popular meteor package named publishComposit, when I tried Loop in Children's find, I got undefined in children i.e below
publishComposite('compoundCompanies', {
find() {
// Find top ten highest scoring posts
return Companies.find({
owner: this.userId
}, {sort: {}});
},
children: [
{
find(company) {
let cursors = company.peoples.forEach(peopleId => {
console.log(peopleId)
return Meteor.users.find(
{ _id: peopleId },
{ fields: { profile: 1 } });
})
//here cursor undefined
console.log(cursors)
return cursors
}
}
]
});
and if I implement async loop in children's find I got error like below code
publishComposite('compoundCompanies', {
find() {
// Find top ten highest scoring posts
return Companies.find({
owner: this.userId
}, {sort: {}});
},
children: [
{
async find(company) {
let cursors = await company.peoples.forEach(peopleId => {
console.log(peopleId)
return Meteor.users.find(
{ _id: peopleId },
{ fields: { profile: 1 } });
})
//here cursor undefined
console.log(cursors)
return cursors
}
}
]
});
the error occured in above code is Exception in callback of async function: TypeError: this.cursor._getCollectionName is not a function
I don't know what I am exactly doing wrong here, or implementing package function not as intended any help will be greatly appropriated
EDIT: my desired result should be full user documents instead of ID no matter it mapped in same peoples array or as another fields I just want as below
{
_id: "dYo4tqpZms9j8aG4C",
owner: "yjzakAgYWejmJcuHz",
name: "Labbaik Waters",
peoples: [
{
profile: {firstName: "Abdul", lastName: "Hameed"},
_id: "yjzakAgYWejmJcuHz"
}
],
createdAt: "2019-09-18T15:33:29.952+00:00"
}
I ran into a similar problem couple of days ago. There are two problems with the provided code. First, using async; it's not needed and rather complicates things. Second, publishComposite relies on receiving one cursor not multiple within its children to work properly.
Below is a snippet of the code used to solve the problem I had, hopefully you can replicate it.
Meteor.publishComposite("table.conversations", function(table, ids, fields) {
if (!this.userId) {
return this.ready();
}
check(table, String);
check(ids, Array);
check(fields, Match.Optional(Object));
return {
find() {
return Conversation.find(
{
_id: {
$in: ids
}
},
{ fields }
);
},
children: [
{
find(conversation) {
// constructing one big cursor that entails all of the documents in one single go
// as publish composite cannot work with multiple cursors at once
return User.find(
{ _id: { $in: conversation.participants } },
{ fields: { profile: 1, roles: 1, emails: 1 } }
);
}
}
]
};
});

How do I return the result of a recursive fetch?

I have the first asynchronous function
fetch("https://api.priceapi.com/v2/jobs", {
body: body,
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
method: "POST"
}).then((response) => {
return response.json();
}).then((data) => {
return fetchRepeat(data.job_id)
})
And the second recursive asynchronous function.
function fetchRepeat(id){
fetch("https://api.priceapi.com/v2/jobs/"+ id +"/download.json?token=" + priceapisecret.secret)
.then((response) => {
return response.json()
}).then((data) =>{
if(data.status == "finished"){
var bookdata = {
title: data.results[0].content.name,
price: data.results[0].content.price
}
return bookdata;
}
else{
fetchRepeat(id)
}
})
}
I want to be able to access bookdata in the first async function. How do I do that?
In order to talk about a return your fetchRepeat needs to return the promise. It did not so returning undefined was the result. The last then also didn't return the value of the recursion and thus also resolved to undefined.
Here is a working version:
function fetchRepeat(id) {
// return the promise
return fetch(`https://api.priceapi.com/v2/jobs/${id}/download.json?token=${priceapisecret.secret}`)
.then(response => response.json())
.then(({ status, results: [{ content: { name: title, price } }] = [{ content: {} }] }) =>
(status === 'finished' ? { title, price } : fetchRepeat(id))); // return result of recursion
}
Now I let ESLint handle the formatting and since I use airbnb it prefers destructuring. The error in the last then was obvious since ELSint complained about consistent return. I urge you to use a linter and an IDE which enforces a coding style to reduce bugs in your code and make it easier for others to read.

performance remote el-select option 3000 items slow and crush?

Hello this is my first time. I have problem with like that I have 3000 items and I use framework like vue, element-ui and meteor. I pull all the items through a remote el-select that selects to add more remote select array object.I don't know why it slow performance and crush.
This is my picture
// Find item opts method
_getItemOpts(query, type) {
type = type || 'remote'
let exp = new RegExp(query)
let selector = {}
if (exp) {
selector = {
itemType: { $ne: 'Bundle' },
// , 'Sale'
activityType: { $in: ['Purchase'] },
status: 'Active',
$or: [
{ name: { $regex: exp, $options: 'i' } },
{ refNo: { $regex: exp, $options: 'i' } },
{ barcode: { $regex: exp, $options: 'i' } },
],
}
}
// Find item
findItems
.callPromise({ selector: selector })
.then(result => {
// console.log(result)
if (type == 'remote') {
this.itemOpts = result
}
this.loading = false
})
.catch(err => {
this.loading = false
Notify.error({ message: err })
})
},
Please help me.
Well no magick is here. U tryin to add to DOM 3000 of elements, so no wonder its crashes. Try to narrow results, for example show them only when user enters 3 letters

Meteor collections: upsert w/ array

Forms of this question have been asked a few times, but I've been unable to find a solution:
I have a schema like this (simplified):
StatusObject = new SimpleSchema({
statusArray: [statusSchema]
});
where statusSchema is
{
topicId:{
type: String,
optional: true
},
someInfo:{
type: Number,
optional: true,
decimal: true
},
otherInfo:{
type: Number,
optional: true
}
}
I am trying to upsert - with the following meteor method code:
var upsertResult = BasicInfo.update({
userId: this.userId,
statusArray: {
$elemMatch: { topicId : newStatus.topicId }
}
}, {
$set: {
"statusArray.$.topicId": newStatus.topicId,
"statusArray.$.someInfo": newStatus.someInfo,
"statusArray.$.otherInfo": newStatus.otherInfo
}
}, {
multi: true,
upsert: true
});
But I keep getting an error: statusArray must be an array
I thought by adding the $, I was making sure it is recognized as an array? What am I missing?
It seems (after your clarification comments), that you want to find a document with particular userId and modify its statusArray array using one of these scenarios:
Update existing object with particular topicId value;
Add a new object if the array doens't have one with particular topicId value.
Unfortunately, you can't make it work using just one DB query, so it should be like this:
// try to update record
const updateResult = BasicInfo.update({
userId: this.userId,
'statusArray.topicId': newStatus.topicId
}, {
$set: {
"statusArray.$": newStatus
}
});
if (!updateResult) {
// insert new record to array or create new document
BasicInfo.update({
userId: this.userId
}, {
$push: {
statusArray: newStatus
},
$setOnInsert: {
// other needed fields
}
}, {
upsert: true
});
}
Your code is treating StatusArray as an object,
Before you do the upsert, build the status array first, assuming that your current value is currentRecord
newStatusArray = currentRecord.statusArray
newStatusArray.push({
topicId: newStatus.topicId,
someInfo : newStatus.someInfo,
otherInfo: newStatus.otherInfo
})
and in the upsert, simply refer to it like this
$set: { statusArray: newStatusArray}

Resources