Add snapshot.val & snapshot.key to an array while I´m subscribed - javascript

I´m gonna break my head with a stone ^^"
I have this code:
this.af.database.list('/Documentos', { preserveSnapshot: true })
.subscribe(snapshots => {
snapshots.forEach(snapshot => {
console.log(snapshot.key, snapshot.val());
});
})
With that I extract all the data correctly, but now I want to add to an object array or something like that (I started few weeks ago with Firebase + Angular2).
I wanna fill that array to load the [ng2 smart table] and if I´m thinking partially well with a properly well-formed array I will fill the table but I don´t know how. Hope anyone can help.

If you want an map (object) with key: value, you can easily do this with Array.prototype.reduce():
const map = snapshots.reduce((map, snapshot) => {
map[snapshot.key] = snapshot.val();
}, {});

Well, according to the example : https://akveo.github.io/ng2-smart-table/#/examples/using-filters ...
(You can find the source code here: https://github.com/akveo/ng2-smart-table/blob/master/src/app/pages/examples/filter/basic-example-source.component.ts)
... you have to put your data in a JSON object :
settings = {
columns: {
id: {
title: 'ID',
filter: false,
},
name: {
title: 'Full Name',
filter: false,
},
username: {
title: 'User Name',
filter: false,
},
email: {
title: 'Email',
filter: false,
}
}
};
data = [
{
id: 1,
name: 'Leanne Graham',
username: 'Bret',
email: 'Sincere#april.biz',
},
{
id: 2,
name: 'Ervin Howell',
username: 'Antonette',
email: 'Shanna#melissa.tv',
}
];
"settings" contain your columns names and "data" must match the columns from "settings".
It would be easier if we knew a bit more of your code (columns of your table + data returned by your service), but I assume something like that would work :
data = [];
this.af.database.list('/Documentos', { preserveSnapshot: true })
.subscribe(snapshots => {
snapshots.forEach(snapshot => {
data.push(
{ [snapshot.key]: snapshot.val() }
);
});
})
Please note that this will create a JSON array with only one key/val per row. We do need to know more about your data to give you a propre answer.

Ok, I found the solution with a simple Array() x)
this.af.database.list('/Documentos', { preserveSnapshot: true })
.subscribe(snapshots => {
snapshots.forEach(snapshot => {
let length = todo.documentos.push(snapshot.val()); // documentos is an array in the class
todo.source.load(todo.documentos);
});
});

Related

Node.js: Mongoose filter data from array of ObjectIDs stored in collection [duplicate]

This question already has answers here:
mongodb/mongoose findMany - find all documents with IDs listed in array
(9 answers)
Closed 3 months ago.
I am trying to search using node.js, ejs and mongoose. All the filter parameters are working perfectly but only categoryIds is not (stored as a collection of ObjectIDs in the mongodb document, referring to the respective document in categories collection), always giving me the empty record set.
For example:
If I need to find the a movie called Cosmos (see the attached screenshot) then I can easily find it with all or any filter except categories. Once I select any category, the record-set will go blank even if the I have selected the one which it belongs to.
model.js
const Model = mongoose.model('Movie', new Schema({
...
categoryIds: [{
type: Schema.Types.ObjectId,
trim: true,
default: null,
ref: 'Category',
}],
copyrightId: {
type: Schema.Types.ObjectId,
trim: true,
default: null,
ref: 'Copyright',
},
...
}, {
timestamps: true
});
Controller.js
Router.get('/', (req, res) => {
const search = req.query;
const conditions = (() => {
let object = {};
['releaseYear', 'languageId', 'copyrightId'].forEach(filter => {
if (search[filter] != '') {
object[filter] = search[filter];
}
});
if (typeof search.categoryIds !== 'undefined') {
object.categoryIds = [];
search.categoryIds.forEach(item => object.categoryIds.push(item));
}
if (search.keywords != '') {
object.title = {
$regex: search.keywords,
$options: 'i'
};
}
return object;
})();
const count = await Model.count(conditions);
const items = await Model.find(conditions, {
__v: false,
imdb: false,
trailer: false,
createdAt: false,
updatedAt: false,
}).sort({
status: -1,
releaseYear: -1,
title: 1
})
.populate('languageId', ['title'])
.populate('copyrightId', ['title'])
.populate('categoryIds', ['title'])
.skip(serialNumber)
.limit(perPage);
...
});
All the fields in the search form
{
categoryIds: [
'6332a8a2a336e8dd78e3fe30',
'6332a899a336e8dd78e3fe2e',
'6332a87ba336e8dd78e3fe2c',
'634574ab339b1a6b09c1e144'
],
languageId: '',
copyrightId: '',
releaseYear: '',
rating: '',
seen: '',
status: '',
keywords: '',
submit: 'search' // button
}
filtered search parameters
{
categoryIds: [
'6332a8a2a336e8dd78e3fe30',
'6332a899a336e8dd78e3fe2e',
'6332a87ba336e8dd78e3fe2c',
'634574ab339b1a6b09c1e144'
]
}
Here is the screenshot of mongodb document.
...
if (typeof search.categoryIds !== 'undefined') {
object.categoryIds = {
$in: []
};
search.categoryIds.forEach(item => object.categoryIds.$in.push(
mongoose.Types.ObjectId(item))
);
}
console.log(object);
return object;
The is the final filter object
{
categoryIds: {
'$in': [
new ObjectId("6332a87ba336e8dd78e3fe2c"),
new ObjectId("634669f4a2725131e80d99f1")
]
}
}
Now, all the filters are working perfectly.
Thank you everyone.
The filter should contain all categoryIds and in the same order to match the document. It's not quite clear from the question if it is the intended functionality. If not, most popular usecases are documented at https://www.mongodb.com/docs/manual/tutorial/query-arrays/
I don't recall how mongoose handles types when you query with array function like $all, so you may need to convert string IDs to ObjectIDs manually, e.g.:
search.categoryIds.forEach(item => object.categoryIds.push(
mongoose.Types.ObjectId(item))
);

Retrieving values from array throws error javacript

I am having an array with following values:
[
{
'Admin1': {
id: 'fa1b2731'
},
'Admin2': {
id: '7b5ab064'
},
'Admin3': {
id: '9f462511'
},
'Admin4': {
id: 'aa82421d'
},
'Admin5': {
id: '34cb2b'
},
'Admin6': {
id: 'ff71ffdd'
},
'Admin7': {
id: 'b57ac9e7'
}
}
]
The code i am trying to retrieve each user id from above array is throwing an error->expected undefined not to be undefined
Following is the code snippet:
if (userArray) {
for (const user of Object.values(userArray)) {
const delUserRes = await userApi.deleteUserById({
token: accessToken,
organizationId: orgid;,
userId: user.id
});
the above method reads the userarray corectly but never assign each id to userId form user.id and throws error
The array in example is having one item, what i mean to get user.id you should call array[0].['Admin1'].id. In your code you doing it like array.['Admin1'].id, so thats why it can't find user.id.
try something like this
if (userArray) {
for (const user of Object.values(userArray[0])) {
const delUserRes = await userApi.deleteUserById({
token: accessToken,
organizationId: orgid;,
userId: user.id
});
Your all the user are in single element of array object at 0 index.
try below code
for (const user of Object.values(userArray[0])) {
console.log(user)
}
Basically you are trying to get values from an object inside an array, so the Object.values doesn't make sense in your code. You can simply use userArray[0] in your for loop or map like:
var data = [ { 'Admin1': { id: 'fa1b2731' }, 'Admin2': { id: '7b5ab064' }, 'Admin3': { id: '9f462511' }, 'Admin4': { id: 'aa82421d' }, 'Admin5': { id: '34cb2b' }, 'Admin6': { id: 'ff71ffdd' }, 'Admin7': { id: 'b57ac9e7' } } ]
Object.values(data[0]).map(user => { //your logic here } );

Mongoose delete other objects after update

I'm having trouble with my update query on mongoose. I'm not sure why other objects get deleted after I update a specific object. the code works when I update but after that, the rest of the objects inside the array are getting deleted/removed. Literally, all of the remaining objects get deleted after the update request.
export const updateProduct = async (req,res) => {
const { id } = req.params;
try {
if(!mongoose.Types.ObjectId.isValid(id)) return res.status(404).json({ message: 'Invalid ID' });
await OwnerModels.findOneAndUpdate({'_id': id, store:{$elemMatch: {productname: req.body.store[0].productname }}},
{$set:
{
store:
{
productname: req.body.store[0].productname,
price: req.body.store[0].price,
quantity: req.body.store[0].quantity,
categoryfilter: req.body.store[0].categoryfilter,
description: req.body.store[0].description,
timestamp: req.body.store[0].timestamp
}
}
}, // list fields you like to change
{'new': true, 'safe': true, 'upsert': true});
} catch (error) {
res.status(404).json(error)
} }
I'm not sure why other objects get deleted after I update a specific object.
Because you are updating the whole object and it will replace the existing store array of object in the database,
You need to use arraFilters, and upsert is not effective in array of object updated, so i have commented,
await OwnerModels.findOneAndUpdate(
{
'_id': id,
store:{
$elemMatch: {
productname: req.body.store[0].productname
}
}
},
{
$set: {
store: {
"store.$[s].productname": req.body.store[0].productname,
"store.$[s].price": req.body.store[0].price,
"store.$[s].quantity": req.body.store[0].quantity,
"store.$[s].categoryfilter": req.body.store[0].categoryfilter,
"store.$[s].description": req.body.store[0].description,
"store.$[s].timestamp": req.body.store[0].timestamp
}
}
},
{
'arrayFilters': [
{ "s.productname": req.body.store[0].productname }
],
'new': true,
'safe': true,
// 'upsert': true
}
);

Set correct value for each property in an object

I have a problem in pushing input into array. I have an array with some properties and I'm going to push some value into it, but I have no idea how to tell which value is for which property.
This is my array that I want to push into it:
validInput: [{
image: avatar1,
name: '',
email: '',
passwrod: '',
phone: '',
revenue: '',
create_date: '',
age: '',
id: ''
}]
This is my function that pushes into the array:
validation(value, REGEX) {
if (REGEX.test(value) === true) {
this.state.validInput.push(value);
this.setState({
validInput: this.state.validInput
});
} else {
console.log('error');
}
}
If I understood correctly and you wish to convert your object inside validInput array into an array of objects you can do this:
Let's say we are looking to get an array of objects with the following format:
{keyName:key,keyValue:value}
we can do something like that:
const newArray = new Array();
Object.keys(this.validInput[0])
.forEach(singleKey => {
newArray.push({
keyName:singleKey,
keyValue:this.validInput[0][singleKey]
})
})
// finally - we will have the newly formatted array in newArray
I think you should have some unique way of identifying the object you want for filtering process like id, name etc. For modified function,
validation(id, value, REGEX) {
if(REGEX.test(value)){
this.state.validInput.map((user) => {
if(user.id === id) {
user.PROPERTY_YOU_NEED_TO_UPDATE = value
}
}
}
}
Since this validInput might receive another object better use to identify it using if(user.id === id). If validInput won't receive another there is no point to use array of objects.
validInput: {
image: avatar1,
name: '',
email: '',
passwrod: '',
phone: '',
revenue: '',
create_date: '',
age: '',
id: ''
}
If it's like above you can just edit the property you want...
this.setState(state => {
let user = Object.assign({}, state.validInput);
user.PROPERTY_YOU_NEED_TO_UPDATE = value;
return { user };
})

two axios requests, one response

it appears the api im using breaks a list of 250 assets into multiple pages. im trying to call numerous pages to be listed in an ant design table
constructor(props) {
super(props);
this.state = {
data: [],
loading: true
}
}
componentDidMount() {
axios.all([
axios.get('https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd&order=market_cap_desc&per_page=250&page=1&sparkline=true&price_change_percentage=24hr'),
axios.get('https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd&order=market_cap_desc&per_page=250&page=2&sparkline=true&price_change_percentage=24hr')
])
.then(axios.spread((res => {
const data = res.data;
this.setState({ data, loading: false })
})))
}
render() {
const { data } = this.state;
const tableData = data.map(row => ({
Rank: row.market_cap_rank,
Symbol: row.symbol,
Name: row.name,
Price: row.current_price,
marketCap: row.market_cap,
priceChange: row.price_change_percentage_24h,
sparkline: row.sparkline_in_7d.price
}))
const columns = [{
title: 'Rank',
dataIndex: 'Rank',
key: 'market_cap_rank',
}, {
title: 'Symbol',
dataIndex: 'Symbol',
key: 'symbol',
render: (value) => {
return <span>{value.toUpperCase()}</span>;
},
}, {
title: 'Name',
dataIndex: 'Name',
key: 'name',
}, {
title: 'Price',
dataIndex: 'Price',
key: 'current_price',
render: (value) => {
return <span>$<b>{value.toFixed(2)}</b></span>;
},
}, {
title: 'Market Cap',
dataIndex: 'marketCap',
key: 'market_cap',
render: (value) => {
return`$${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
},
...
<Table
pagination="false"
loading={this.state.loading}
dataSource={tableData}
columns={columns}
size="small"
/>
this works, but only displays the first page and not the second as well
sorry for the silly question, maybe someone can take a moment to assist me as this question probably stems from a lack of general understanding. it's sure nice to hear from other people on here! :)
You have to update your componentDidMount like below
axios.all([
axios.get('https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd&order=market_cap_desc&per_page=250&page=1&sparkline=true&price_change_percentage=24hr'),
axios.get('https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd&order=market_cap_desc&per_page=250&page=2&sparkline=true&price_change_percentage=24hr')
])
.then(resArr =>{
const data = [];
resArr.map(res=> data.push(...res.data));
this.setState({ data, loading: false });
});
This is because the function you pass to axios.spread receives the result of the requests in two different arguments.
Like in the example from the axios doc
function getUserAccount() {
return axios.get('/user/12345');
}
function getUserPermissions() {
return axios.get('/user/12345/permissions');
}
axios.all([getUserAccount(), getUserPermissions()])
.then(axios.spread(function (acct, perms) {
// Both requests are now complete
}));
your axios.spread will receive separately the two pages :
You can then concatenate the two pages to have your data
axios
.all([
axios.get('https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd&order=market_cap_desc&per_page=250&page=1&sparkline=true&price_change_percentage=24hr'),
axios.get('https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd&order=market_cap_desc&per_page=250&page=2&sparkline=true&price_change_percentage=24hr')
])
.then(axios.spread(((page1, page2) => {
const data = [...page1.data, ...page2.data];
this.setState({ data, loading: false })
})))
If you want to have more than a determinate number of pages you can make use of rest operator and flatten the array using spread and concat
axios
.all(arrayOfLinks)
.then(axios.spread(((...pages) => { // use rest operator to get an array of pages containing your data
const data = [].concat(...pages.data); // use spread operator in a concat to flatten your arrays of data
this.setState({ data, loading: false })
})))

Categories