Combining two arrays when a promise resolves in vue js - javascript

I have this data i have held in this variable this.roomsData.room_photos
[ { "url": "https://api.example.com/uploads/609ee58907166.jpg" }, { "url": "https://api.example.com/uploads/609ee5898ba19.jpg" }, { "url": "https://api.example.com/uploads/609ee58994a10.jpg" }, { "url": "https://api.example.com/uploads/609ee589af635.jpg" }, { "url": "https://api.example.com/uploads/609ee589b0fc7.jpg" }, { "url": "https://api.example.com/uploads/609ee589cd79f.jpg" }, { "url": "https://api.example.com/uploads/609ee589d8d27.jpg" } ]
and this data
[ { "url": "https://api.example.com/uploads/609eeded64530.jpg" }, { "url": "https://api.example.com/uploads/609eeded68ebe.jpg" }, { "url": "https://api.example.com/uploads/609eeded6a6bc.jpg" } ]
i have in this variable this.roomsData.edit_room_photos and its being generated from
uploadRoomImages: async function (file, progress, error, options) {
try {
console.log(file, options);
const formData = new FormData()
formData.append('room_photos', file)
const result = await fetch('https://api.example.com/uploads_scripts/rooms.php', {
method: 'POST',
body: formData
})
progress(100) // (native fetch doesn’t support progress updates)
return await result.json()
} catch (err) {
error('Unable to upload file')
}
},
and this is the component
<FormulateInput
type="image"
name="room_photos"
v-model="roomsData.edit_room_photos"
label="Select Room Images To Upload"
help="Select a png, jpg,webp or gif to upload."
validation="required|mime:image/jpeg,image/png,image/gif,image/webp"
:uploader="uploadRoomImages"
error-behavior="live"
multiple
/>
Since there is data already in this variable this.roomsData.room_photos , how can i add the data in this variable this.roomsData.room_photos
to data i get from waiting for my function to resolve and store the data here this.roomsData.edit_room_photos
I have tried object assign and array concat on the form submit handler but that results to cyclic json errors.
I want to add the data in the two arrays together without removing the duplicates. How can i combine the two arrays together without removing duplicates.

You can use a computed value with a setter:
computed: {
room_photos: {
get: function () {
return [...this.roomsData.room_photos, ...this.roomsData.edit_room_photos];
},
set: function (newValue) {
this.roomsData.edit_room_photos = newValue.slice(this.roomsData.room_photos.length);
},
},
},

If the result of uploadRoomImages() leads to the value of roomsData.edit_room_photos, you could just modify the return value of uploadRoomImages() to .concat the other array:
uploadRoomImages: async function (file, progress, error, options) {
try {
//...
const result = await result.json()
return result.concat(this.roomsData.room_photos)
} catch (err) {
error('Unable to upload file')
}
},
Note Array.prototype.concat() does not filter out duplicates, so there's no need to be concerned about losing duplicate entries in this case.

Related

Cypress - how to send parameters to same function inside it's callback

I'm trying to implement fixtures in my cypress project to avoid repeatedly sending same requests.
Command "ReadFixture" returns data from fixture file:
Cypress.Commands.add("ReadFixture", (fixtureName, firstKey, secondKey = "") => {
let fixturePath = `cypress/fixtures/${fixtureName}.json`;
if (secondKey.length === 0) {
cy.readFile(fixturePath).then(fixture => {
let dataArray = [];
let fixtureKeys = Object.keys(fixture);
fixtureKeys.forEach(key => {
let data = fixture[key][firstKey];
dataArray.push(data);
});
return cy.wrap(dataArray);
});
}
else {
cy.readFile(fixturePath).then(fixture => {
let dataArray = fixture[secondKey][firstKey];
});
return cy.wrap(dataArray);
};
});
Data is in json structure:
{
"id_0": {
"id": "id_0",
"more_data": [
"string_0"
]
},
"id_1": {
"id": "id_1",
"more_data": [
"string_1",
"string_2"
]
}
}
For some tests, only "id" is required, such test example:
it("Level 1", () => {
cy.ReadFixture("fixture_name", "id").then(urlKeys => {
urlKeys.forEach(keyUrl => {
cy.request({
method: "GET",
url: `${reqUrl}/${keyUrl}`
}).then(response => {
expect(response.status).to.be.equal(200);
});
});
});
})
Everything works as expected, however, for other tests "more_data" of single "id" is required. My approach is to read fixture twice - first get array of "id", like in "Level 1" test, then get "more_data" for each "id" in array. Example:
it("Level 2", () => {
cy.ReadFixture("fixture_name", "id").then(urlKeys => {
urlKeys.forEach(keyUrl => {
cy.ReadFixture("fixture_name", "more_data", keyUrl).then(keyData => {
cy.request({
method: "GET",
url: `${reqUrl}/${keyUrl}/more_data`
}).then(response => {
expect(response.status).to.be.equal(200);
expect(response.body.more_data).to.be.eql(keyData);
});
});
});
});
});
Problem is, when
cy.ReadFixture("fixture_name", "more_data", keyUrl)
is called, keyUrl is not defined for it and command returns array of "more_data" from all "id" because of if statement. Also, keyUrl can't be passed to request. Is it possible to go around this issue or the method I'm using is completely wrong?
try changing your else block to wrap the values inside your then callback:
else {
cy.readFile(fixturePath).then(fixture => {
let dataArray = fixture[secondKey][firstKey];
return cy.wrap(dataArray);
});
};

Determining pr eliminating empty key:value from an object for multiple filtering purposes

My app has a feature where users can filter results based on "blood group" and "city", and areas. Results will be retrieved from DB using Axios for Vuejs through "URL" query strings. Example url is: http://example.com/api/results?blood=a+&city=london
It should work in a way that when a user select just blood group from select menu: the url would exclude the city parameter. But from my current code, I can't get it stripped of, as a result, the database query returns no results on the basis that cityreturns null value.
Here's what I have in my Vue component:
<script>
export default {
props: ['user'],
data() {
return {
auth_user: this.user,
results: {},
blood_groups: "",
cities: "",
districts: "",
areas: "",
donorUrl: "/api/donors",
requestedBlood: "",
requestedCity: "",
requestedDist: "",
requestedArea: "",
params: {}
};
},
created() {
this.fetchDonors();
this.fetchCities();
},
methods: {
fetchDonors() {
let url = "/api/donors";
axios.get(url).then(response => {
this.results = response.data.data;
this.blood_groups = [...new Set(response.data.data.map(x=> x.blood_group))];
});
},
fetchCities() {
let url = "/api/location_type/cities";
axios.get(url).then(response => {
this.cities = response.data.cities
})
},
selected_blood_group(event) {
this.requestedBlood = event.target.value;
this.get();
},
get_city(event) {
this.requestedCity = event.target.value;
this.get();
},
get() {
let request = {
params: {
blood: this.requestedBlood,
city: this.requestedCity,
dist: this.requestedDist,
area: this.requestedArea
}
}
axios.get('/api/donors', request).then(response => {
this.results = response.data.data
})
}
},
};
</script>
My query is how can I remove or check if any of the following properties contains empty value, so that I do not include them in axios params?
let request = {
params: {
blood: this.requestedBlood,
city: this.requestedCity,
dist: this.requestedDist,
area: this.requestedArea
}
}
You can try below code.
Create a new object(called testParams) and add that object in params.suppose requestedCity is selected(not only but any variable is selected ). Then you can do like below.
if(requestedCity.length!=0)
{
testParams["city"]=requestedCity; // OTHERWISE DON'T ADD IN testParams object
}
Finally while making request through axios add testParams in params object like below.
axios.get('/yourUrl/',{
params:{
testParams //here vue will automatically sets 'testParams':testParams
}
})
I got it working with the following approach:
let request = {
blood: this.requestedBlood,
city: this.requestedCity,
dist: this.requestedDist,
area: this.requestedArea
}
for(let k in request)
if(!request[k]) delete request[k];
axios.get('/api/donors', {
params: request
}).then(response => {
this.results = response.data.data
})

Mongodb - Update property per object in array of object, Insert if doesn't exists

I wish to update a property per object in array of objects, but if some of the objects doesn't exists, insert the object instead.
Currently I used "upsert", which creates a new document when no document matches the query, unfortunately it is replacing a single item with my entire list.
Worth to mention that I am using mongoist to perform an async requests.
My code:
this.tokenArray = [
{ token: "654364543" },
{ token: "765478656" },
{ token: "876584432" },
{ token: "125452346" },
{ token: "874698557" },
{ token: "654364543" }
]
database.upsertDatebaseItem(this.tokenArray.map(x => { return x.token }), { valid : true }, 'Tokens');
async upsertDatebaseItem(itemKey, itemValue, collectionName) {
try {
await this.database[collectionName].update({ token : { $in: itemKey}}, { $set: itemValue }, {upsert : true} , {multi : true});
} catch (error) {
console.log(`An error occurred while attempting to update ${itemType} to the database: ${error}`);
return false;
}
}
Found the way to do it:
const bulkUpdate = this.tokenArray.map((x) => {
return {
"updateOne": {
"filter": { "token": x.token },
"update": { "$set": { "valid": true } },
"upsert": true
}
};
});
and:
this.database[collectionName].bulkWrite(bulkUpdate);
To upsert with mongoist, use the following:
var bulk = db.collection.initializeOrderedBulkOp()
for(var doc of docs) bulk.find( { _id: doc._id } ).upsert().updateOne(doc); // or use replaceOne()
await bulk.execute();
Converted to your case that would be
var bulk = db.collectionName.initializeOrderedBulkOp()
for(var tokenItem of tokenArray) bulk.find( { token : tokenItem.token } ).upsert().updateOne(tokenItem); // or use replaceOne()
await bulk.execute();

How to search in a REST API express with multiple fields

I would like to perform a search request like https://api.mywebsite.com/users/search?firstname=jo&lastname=smit&date_of_birth=1980
I have a User schema like:
var UserSchema = new mongoose.Schema({
role: { type: String, default: 'user' },
firstname: { type: String, default: null },
lastname: { type: String, default: null },
date_of_birth: { type: Date, default: null, select: false },
});
What I did so far with stackoverflow help:
// check every element in the query and perform check function
function search_t(query) {
return function (element) {
for (var i in query) {
if (query[i].function(element[i], query[i].value) == false) {
return false;
}
}
return true;
}
}
// prepare query object, convert elements and add check function
// convert functions are used to convert string (from the query) in the right format
// check functions are used to check values from our users
function prepareSearch(query, cb) {
let fields = {
"firstname": {
"type": "string",
"function": checkString,
"convert": convertString
},
"lastname": {
"type": "string",
"function": checkString,
"convert": convertString
},
"date_of_birth": {
"type": "date",
"function": checkDate,
"convert": convertDate
}
};
for (let k in query) {
k = k.toLowerCase();
if (!(k in fields)) {
return cb({message: "error"});
}
query[k] = {value: fields[k].convert(query[k]), function: fields[k].function};
}
return cb(null, query);
}
// linked to a route like router.get('/search/', controller.search);
export function search(req, res) {
return User.find({}).exec()
.then(users => {
return prepareSearch(req.query, (err, query) => {
if (err) {
return handleError(res)(err);
} else {
return res.status(200).send(users.filter(search_t(query)));
}
});
})
.catch(handleError(res));
}
So this code works but I don't know if it's a good thing. I have a lot of other fields to check (like gender, ....) and I don't know if it's a good thing to do it "manually".
I don't know if mongoose has any function to do it.
Should I use another method to filter / search in my users in my REST API ?
I'm pretty new here and I am not sure about how I work...
Thank you,
Ankirama

Join query with ElasticSearch

I need to do a join query on firebase using elasticsearch,
can anyone help me?
In particular I have two nodes, in the child node I have a field that is the id of the father node and I would like to have as a result all the fields of the father node.
How do I build my index in the code?
In adding, in my client I use elasticsearchclient,
here is an extract of the code to index a node:
var db = admin.database();
var etest = db.ref(type);
etest.on('child_added', createOrUpdateIndex);
etest.on('child_changed', createOrUpdateIndex);
etest.on('child_removed', removeIndex);
function createOrUpdateIndex(snap) {
client.index(index, type, snap.val(), snap.key)
.on('data', function(data) { console.log('indexed', snap.key + data ); })
.on('error', function(err) { console.log('index error ', err); }).exec();
}
function removeIndex(snap) {
client.deleteDocument(index, type, snap.key, function(error, data) {
if( error ) console.error('failed to delete', snap.key, error);
else console.log('deleted', snap.key);
});
}
And to take query results:
var queue = db.ref("search");
queue.child('request').on('child_added', processRequest);
function processRequest(snap) {
console.log('process...... ');
snap.ref.remove(); // clear the request after we receive it
var data = snap.val();
// Query ElasticSearch
client.search(index, data.type, { "query": { 'query_string': {
"query" : data.query
}}})
.on('data', function(results) {
var res = JSON.parse(results);
console.log(JSON.stringify(res.hits));
console.log("TOTAL " + JSON.stringify(res.hits.total));
queue.child('response/'+snap.key).set(results);
})
.on('error', function(error){ console.log("errore"); }).exec();
}
Thank you in advance
There are two ways to store your data.
First is creating a nested doc. This is helpful if you need to perform search on some of the values and need other info only for the display.
PUT /my_index {
"mappings": {
"yourIndex": {
"properties": {
"yourColumn": {
"type": "nested",
"properties": {
"name": { "type": "string" },
"parentNode": { "type": "string" },
"childNode": { "type": "string" }
}
}
}
}}}
Eg.
'str1', 'parent1', 'child1'
'str2' 'parent1', 'child2'
If you need not maintain any hierarchy,
you can simply create 3 separate columns and store like a flat data.
You can specify parent1 id and search for all the docs in both the cases.

Categories