Saving all items to a firebase collection as individual documents - javascript

I have a function where a user types in there sitemap and it returns all the links in there sitemap.
How can I then save all of those links in individual documents in a specific collection on Firebase?
See below for the current firebase set function. Erro returns "Function DocumentReference.set() called with invalid data. Data must be an object, "
const saveAllCrawl = async () => {
await db.collection('urls').doc('test').set(urls);
}
Current map of the array the sitemap crawler returns & Scrap Sitemap function
const scrapeSitemap = async (e) => {
e.preventDefault();
console.log(sitemapURL)
const array = await GetSitemapLinks(sitemapURL);
setURLS(array)
}
{urls && urls.map((user) => (
<Grid container spacing={0} >
<Grid xs={6} sm={6} md={6}>
<li className="user">{user}</li>
</Grid>
</Grid>
))}
<Button onClick={saveAllCrawl}>Save All To Firebase</Button>

In document every value is being stored against a key.
Like if there are multiple urls and you want to store each in a separate document so you have to stored them against any key.
Collections: URLS
Document Id : (generated_key)
Document Data :
{ "key" : "url_value" }
So, as mentioned above for this you have to create a batch in which you assign all queries to a batch and after that set batch.commit().
Now, if you are trying to store them in a list like an array.
{
"urls": [
"url_one",
"url_one"
]
}
So, first create an object and assigned all string values to key and then set that to a document.

Related

How can I map through several arrays of objects using JSX in React?

I have some json data:
{
"shops" :
[
{
"type" : "Blacksmith/Armoury",
"items_light_armour" :
[
"Light Armour",
{
"id": 1,
"item" : "Padded Armour",
"low_price": 15,
"med_price": 20,
"high_price": 30,
"available": true,
"limited": false,
"weight": 8,
"blurb": "AC11. Made of quilted layers of cloth and batting."
},
//...
//three other objects, as array elements, with a similar set of key/value pairs
The first element (inside the items_light_armour array) is just a string to denote what category each data set is.
What I want to do, is display every single object (apart from its ID and blurb) in a table I have. The table generates new rows for every item mapped through.
The problem I have is that it's not mapping out the data as intended.
Here's a picture of what the table looks like at when it first loads:
So the data does map to the table, but only the first item in each array of objects. Im honestly unsure of how to get all of the data for each category.
Specifically, each category should list all of its items, then a new category would open up, list all of its entries like the first and so on until the end of the array is reached, instead of one from each as displayed above.
Here's how I get my data from the JSON file (above my return block in the component):
//get the json data
const jsonData = require("../Reference Files/Json Files/shops.json");
Then, I convert it to a const
const objInnerValues = Object.values(jsonData.shops[0])
Then, in the return block of my component, here's how I 'fill' the table rows.
EDIT: This is the latest code, following advice from #John:
//...
{
<>
objInnerValues.map((things, outerIndex) => (
{outerIndex === 0 ? console.log("outerIndex WAS 0"):
<TableRow key= {outerIndex} onClick={() => BarkItemBlurb(outerIndex)}>
{Object.values(things).map((eachThing, innerIndex) => (
{innerIndex == 0 ? console.log("innerIndex or outerIndex was 0"):
<>
<SuperTD key={innerIndex}>{eachThing.item}</SuperTD>
<SuperTD key={innerIndex+1}>{eachThing.weight}lbs</SuperTD>
<SuperTD key={innerIndex+2}>{eachThing.low_price}gp</SuperTD>
<SuperTD key={innerIndex+3}>{eachThing.med_price}gp</SuperTD>
<SuperTD key={innerIndex+4}>{eachThing.high_price}gp</SuperTD>
</>
})
</TableRow>
})
</>
}
//...
I'm using styled-components, hence the weird html tag names.
Any advice would be greatly appreciated.
This is probably want you want. When you get thing, you map that and you don't need to index it because eachThing is the actual object.
{
objInnerValues.map((things, i) => (
{things.map((eachThing) => (
<TableRow key= {i} onClick={() => BarkItemBlurb(i)}>
<SuperTD>{eachThing.item}</SuperTD>
<SuperTD>{eachThing.weight}lbs</SuperTD>
<SuperTD>{eachThing.low_price}gp</SuperTD>
<SuperTD>{eachThing.med_price}gp</SuperTD>
<SuperTD>{eachThing.high_price}gp</SuperTD>
</TableRow>
)}
))}
Given I haven't ran this due to lack of working code; I may have the wrong number of brackets/closing brackets and may have it in the wrong place but overall it should guide you to a solution.
Thanks to #John for the assist.
I overcomplicated my design. My JSON file contained arrays and objects, making it awkward to navigate.
After restructuring it to contain only arrays, it was a lot easier.
Also, as for the actual problem, I was shown that I needed to add another map function inside my original one to make it spit the data out the right way.
//...
Object.values(thing).map((innerThing, innerIndex) => (
<>
{console.log("\nouter/inner: "+outerIndex +", " +innerIndex)}
{console.log("\nData: \n\t"+innerThing[2] +"\n\t" +innerThing[8] + "\n\t" +innerThing[3]+"\n\t" + innerThing[4]+"\n\t"+innerThing[5])}
<TableRow key = {thing[0].toString()}>
<SuperTD>{innerThing[2]}</SuperTD>
<SuperTD>{innerThing[8]}lbs</SuperTD>
<SuperTD>{innerThing[3]}gp</SuperTD>
<SuperTD>{innerThing[4]}gp</SuperTD>
<SuperTD>{innerThing[5]}gp</SuperTD>
</TableRow>
</>
//...
Now, with the mapping sorted, this is the result:

base64 encoded On-chain NFT not displaying on the Fronted

I'm trying to display all the minted tokens on the front page of my dapp, so I created an array in solidity and pushed the tokenId to it, then tried using a spread operator, and mapping it to the tokenURI's. Unfortunately, I haven't been able to get the image to display it.
for (let i = 1; i <= totalSupply; i++) { //this is listing an array of minted tokens
const tokenURI = await contract.methods.tokenURI(i - 1).call()
const imageURI = await tokenURI.image
// how should we handle the state on the front end
this.setState({
NFTz: [...this.state.NFTz, imageURI] // spread operator
}) // pretty sure the array could be done on the front end
}
console.log(this.state.imageURI)
console.log(this.state.NFTz)
The console returns:
index.js:1437 Warning: Each child in a list should have a unique "key" prop.
Check the render method of `App`. See fb.me/react-warning-keys for more information.
in div (at App.js:136)
in App (at src/index.js:7)
It's rendered it onto MDBcards with:
<div className="row textCenter">
{this.state.NFTz.map((key, imageURI) => {
return (
<div>
<div>
<MDBCard className="token img" style={{ maxWidth: '22rem' }}>
<MDBCardImage src={imageURI} position='top' height='250rem' style={{ marginRight: '4px' }} />
<MDBCardBody>
<MDBCardTitle></MDBCardTitle>
<MDBCardText></MDBCardText>
<MDBBtn href={imageURI}>Download</MDBBtn>
</MDBCardBody>
</MDBCard>
</div>
</div>
PS: Err, probably more efficient to create an array on the front end, instead of in solidity.
Thank you and God Bless

React: useState/useEffect - How to collect 10 items in realtime

I am trying to get 10 usernames back when I type a keystroke.
For now it only gives me a Username back if the username is exactly in the jsonplaceholder list. So when i type "Karia" nothing comes back until I type "Karianne"
So for example if the Input gets the first letter "A", I want to give back the first 10 Items which are matching from the jsonplaceholder list. If I put in an "R", after that, so its "Ar" I want to get back the first 10 matching "Ar" usernames, like Aron, Ariel, Aria, etc.
Does someone have an Idea?
export const Search = () => {
const [user, setUser] = useState(null);
const [searchQuery, setSearchQuery] = useState("")
useEffect(() => {
if (searchQuery.length > 0) {
const fetchFunc = async () => {
const response = await fetch(`https://jsonplaceholder.typicode.com/users?username=${searchQuery}`)
const resJSON = await response.json();
setUser(resJSON[0]);
};
fetchFunc();
}
}, [searchQuery]);
return (
<Flex className={styles.search__container}>
<Flex className={styles.search__elements}>
<InputGroup className={styles.search__input}>
<InputRightElement
className={styles.search__inputElements}
children={<RiSearchLine className={styles.search__icon} />} />
<Input
className={styles.search__users}
type='search'
placeholder='Search'
onChange={event => setSearchQuery(event.target.value)}
/>
{user ? (
<div>
<h3>{user['name']}</h3>
<h3>{user['username']}</h3>
<h3>{user['email']}</h3>
</div>
) : (
<p>No user found</p>
)}
</InputGroup>
</Flex>
</Flex>
)
}
The main limitation here is on the API side. Your API should supply you with the similar names. If it doesn't, then you can't do much.
Maybe the API provides a way to retrieve users with partial names (but I doubt it would be the case).
Otherwise, you can retrieve all users once,and simply display the one that fits your requirements, every time you write something.
To sum up:
When your component is mounted (at the beginning), fetch all users, and store them. You will perform this API call only once.
Then, every time you write something, just take the 10 users that have a name that include what you wrote.
Ideally, this should be handled by the API, and you should be concerned about when to trigger or re-trigger the API call.
API gets you a list of names, you slice a set of 10 from the list of names and set it in users, and then simply map them in your UI.
Also, you could maybe further optimise the function debouncing the API call.

How to filter an array without losing data?

I have a function to filter an array of todos. The array is filtered correctly but when I type some thing else it removes other array elements and doesn't go back.
I've seen a few solutions, but they say "you have to write code in the render function" and I don't use this method because I render the array elsewhere with the help of props. filteredTodos has all local storage data.
How can I filter this data without losing data?
// *** Form.js ***
const filterTodos = (e) => {
const filtTod = filteredTodos.filter((todo) => {
return todo.text.toLowerCase().indexOf(e.target.value.toLowerCase()) !== -1
});
setFilteredTodos([...filtTod]);
};
// it's my render place *** TodoList.js ***
return (
<div className="todo-container">
<ul className="todo-list">
{filteredTodos.map((todo) => {
return (
<Todo
id={todo.id}
key={todo.id}
text={todo.text}
completed={todo.completed}
setTodos={setTodos}
todos={todos}
/>
)
})}
</ul>
</div>
);
const [inputText, setInputText] = useState("");
const [todos, setTodos] = useState([]); // Todos is all array items.
const [status, setStatus] = useState("all");
const [filteredTodos, setFilteredTodos] = useState([]); // the state is for my filter list
The idea with filtering data like an array of todos is to maintain a consistent "reference" or "source" array that represents all of the todos that exist in your app. This reference array may change when the user adds or removes a todo item, and may be persisted to the backend (or local storage, in your case) in some capacity or other. This array is the source of truth.
When a user enters a search/filtering term, filter on the reference/source array of all todos every time rather than the already-filtered result set.
In your code, todos represents the source array and filteredTodos represents the results of a single search. By using filteredTodos.filter, the results either keep diminishing after each filtering query, or there never were any results to work with to begin with -- either way, it's incorrect.
Think of filteredTodos as a temporary snapshot of todos used to show a subset view of todos to match the user's search term.
The fix is to use todos.filter rather than filteredTodos.filter so that you're always searching on the full data set.

Find index in Array of urls

I have an array of URLs and base64 hashed data, and I want to make a function that finds the key of that element in React.js. I have made a handler as such:
showModalSpeceficHandler = (image) =>{
this.state.images.forEach(function(image){
console.log(Object.keys[image]);
})
console.log('someting')
The image property I pass in is the value of the given image. The way the function works now is it returns an array of the keys for each, character in the URL or base64 data. Is there a way, that I can get the index that matches the key of the given object?
Here is the way that I have declared my image objects:
let image= this.state.images.map(image => {
return (
<img
key={image}
src={image}
onClick={() => this.showModalSpeceficHandler(image)}
/>
)
});
Maybe I should give another key instead, would that make my code easier and more maintainable?
The map() function also gives the index in the parameters for the callback: list.map((value,index) => { /* your function */ }). You could use like below:
let image= this.state.images.map((image,index) => {
return <img key={`image-${index}`} src={image}
onClick={() =>this.showModalSpeceficHandler(image)}/>
});

Categories