I have a mobile app written using Apache Cordova. I am using Azure Mobile Apps to store some data.
I created Easy Tables and 1 Easy API. The purpose of the API is to perform delete / update more than 1 record. Below is the implementation of the API.
exports.post = function (request, response){
var mssql = request.service.mssql;
var sql = "delete from cust where deptno in ( ? )";
mssql.query(sql, [request.parameters],{
success : function(result){ response.send(statusCodes.OK, result); },
error: function(err) { response.send(statusCodes.BAD_REQUEST, { message: err}); }
});
}
Is there any other way to implement it ? The del() method on table object on takes id to delete and I didn't find any other approach to delete multiple rows in the table.
I am having difficulty to test the implementation as the changes in the API code is taking 2-3 hours on average to get deployed. I change the code through Azure website and when I run it, the old code is hit and not the latest changes.
Is there any limitation based on the plans we choose?
Update
The updated code worked.
var sql = "delete from trollsconfig where id in (" + request.body.id + ")";
mssql.query(sql, [request.parameters],{
success : function(result){ response.send(statusCodes.OK, result); },
error: function(err) { response.send(statusCodes.BAD_REQUEST, { message: err}); }
});
Let me cover the last one first. You can always restart your service to use the latest code. The code is probably there but the Easy API change is not noticing it. Once your site "times out" and goes to sleep, the code gets reloaded as normal. Logging onto the Azure Portal, selecting your site and clicking Restart should solve the problem.
As to the first problem - there are a variety of ways to implement deletion, but you've pretty much got a good implementation there. I've not run it to test it, but it seems reasonable. What don't you like about it?
Related
Can anyone give me any advice on how to create an LP pool on the Solana devnet?
I planned this job for testing swaps between specific two tokens on the devnet using the Raydium protocol.
So, I need to create a swap pool on the devnet first.
To achieve this, I did it like below.
First of all, to list on the serum market, I cloned the Raydium-Dex repository on my mac and changed the Serum dex's program id from the mainnet to the devnet, and I success registered on the devnet serum. (Custom token with SOL pairs)
As a result, I got a serum market program id.
After that, I cloned the Raydium-frontend repository to create a liquidity pool. And modified wellknownToken.config.ts so that my custom tokens could be possible to create a new pool.
Finally, I could access the create pool UI from the localhost web UI.
I clicked Initialize Liquidity Pool button on the UI and got a Toast message Create a new pool Transaction Sent apparently.
However, It is not worked well. Because I can not find the transaction hash on the Solscan website.
I tracked the button's click event codes and I figured out one thing.
One of the result value of Liquidity.makeCreatePoolTransaction function has a null value, especially, feePayer.
const { transaction: sdkTransaction1, signers: sdkSigners1 } = Liquidity.makeCreatePoolTransaction({
poolKeys: sdkAssociatedPoolKeys,
userKeys: { payer: owner }
})
const testTx = await loadTransaction({ transaction: sdkTransaction1, signers: sdkSigners1 })
console.log('feepayer', testTx.feePayer?.toBase58()) // null
I felt this is not the preferred (good) way to create a swap pool on the Solana devnet, but I can not find a better way to achieve this task.
What am I missing? or What am I should read or learn?
please give me some advice on how to do it to make it works.
Thanks.
It looks like the transaction created with Liquidity.makeCreatePoolTransaction hasn't been sent to the network, so it doesn't exist anywhere. Be sure to send and confirm the transaction before trying to load it. You can use something like:
const { transaction: sdkTransaction1, signers: sdkSigners1 } = Liquidity.makeCreatePoolTransaction({
poolKeys: sdkAssociatedPoolKeys,
userKeys: { payer: owner }
});
await sendAndConfirmTransaction(connection, transaction, [wallet]);
Note that this requires a connection to send and a wallet to sign. More info at https://github.com/solana-labs/solana/blob/9ac2245970de90af30bff9d1f7f35cd2d8f2bf6d/web3.js/src/util/send-and-confirm-transaction.ts#L18
You might run into other issues though, because the Raydium program isn't deployed to devnet: https://explorer.solana.com/address/675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8?cluster=devnet
I am trying to pass a object { key:value} and send it to meteor publish so i can query to database.
My Mongo db database has (relevant datas only) for products:
products : {
categs:['Ladies Top','Gents'],
name : Apple
}
In meteor Publish i have the following:
Meteor.publish('product', (query) =>{
return Clothings.find(query);
})
In client i use the following to subscribe:
let query = {categs:'/ladies top/i'}; // please notice the case is lower
let subscribe = Meteor.subscribe('product',query);
if (subscribe.ready()){
clothings = Products.find(query).fetch().reverse();
let count = Products.find(query).fetch().reverse().length; // just for test
}
The issue is, when i send the query from client to server, it is automatically encoded eg:
{categs:'/ladies%top/i'}
This query doesnot seem to work at all. There are like total of more than 20,000 products and fetching all is not an option. So i am trying to fetch based on the category (roughly around 100 products each).
I am new to ,meteor and mongo db and was trying to follow existing code, however this doesnot seem to be correct. Is there a better way to improve the code and achieve the same ?
Any suggestion or idea is highly appreciated.
I did go through meteor docs but they dont seem to have examples for my scenario so i hope someone out there can help me :) Cheers !
Firstly, you are trying to send a regex as a parameter. That's why it's being encoded. Meteor doesn't know how to pass functions or regexes as parameters afaict.
For this specific publication, I recommend sending over the string you want to search for and building the regex on the server:
client:
let categorySearch = 'ladies top';
let obj = { categorySearch }; // and any other things you want to query on.
Meteor.subscribe('productCategory',obj);
server:
Meteor.publish('productCategory',function(obj){
check(obj,Object);
let query = {};
if (obj.categorySearch) query.category = { $regex: `/${obj.categorySearch}/i` };
// add any other search parameters to the query object here
return Products.find(query);
});
Secondly, sending an entire query objet to a publication (or Method) is not at all secure since an attacker can then send any query. Perhaps it doesn't matter with your Products collection.
Every time you deploy to Firebase hosting a new deploy version is created so you can roll back and see who deployed. This means that each time every file you deploy is stored and occupying more space.
Other than manually deleting each deployed version one by one, is there any automated way to clean those useless files?
You're correct. You'll need to delete the old deployed versions one by one using the Firebase Hosting console.
There's no other way to do this, so I'd suggest you to file a feature request to enable deletion of multiple deployed version in the Firebase Hosting console.
Update:
You can vote here (please avoid +1 spam, use reactions) https://github.com/firebase/firebase-tools/issues/215#issuecomment-314211730 for one of the alternatives proposed by the team (batch delete, keep only X versions, keep versions with published date < Y)
UPDATE Mar/2019
There's now a proper solution: "Version history settings" which allows to keep the last X versions.
https://support.google.com/firebase/answer/9242086?hl=en
UPDATE Feb/2019
Confirmed by Google employee # github.com/firebase/firebase-tools/issues/...
It is actively being worked on. 🙂
🎉🎉🎉
Before continuing reading:
You can vote here (please avoid +1 spamming, use reactions) https://github.com/firebase/firebase-tools/issues/215#issuecomment-314211730 for one of the alternatives proposed by the team
So, by using Chrome Dev tools I found a way to delete multiple versions. Keep in mind it requires a bit for work (proceed with care since deleted versions can't be restored and you won't get any warnings like when using the UI).
Step 1. Retrieving the version list.
Open Chrome Dev Tools (if you don't know how to chances are you should wait for a proper solution by Firebase's team).
Open Firebase's Console and go to the "Hosting" tab.
Go to the "Network" tab on CDT and use the Websockets filter.
Select the request named .ws?v=5&ns=firebase
Open the "Frames" tab
Now comes the tedious part: Select the frames with the highest "length" value. (Depending on your data, it could be 2-n frames. In my case, 3 frames with 14k-16k length)
Paste each of the frame's data in order (which will form a valid JSON object).
Extracting the data: There are several ways to do it. I opted for simple JS on CDT's console.
var jsonString = '...';
var json = JSON.parse(jsonString);
var ids = Object.keys(json.d.b.d);
Step 2. Performing the requests
Almost there :P
Now that you have the IDs, perform the following requests:
DELETE https://firebasehosting.clients6.google.com/v1beta1/sites/PROJECT_NAME/versions/-VERSION_ID?key=KEY
I used Sublime (to create the request strings) + Paw.
The "KEY" can be copied from any of CDT's requests. It doesn't match Firebase's Web API key
=> Before performing the requests: take note of the version you don't want to delete from the table provided by Firebase. (Each version listed on the website has the last 6 digits of it's ID under your email)
(Screenshots weren't provided since all of them would require blurring and a bit of work)
This script is not yet super-solid, so use it at your own risk. I'll try to update it later, but worked for me for now.
Just some javascript to click on buttons to delete deployed items one by one.
var deleteDeployment = function(it) {
it.click()
setTimeout(function() {
$('.md-dialog-container .delete-dialog button.md-raised:contains("Delete")').click()
}, 300)
}
$('.h5g-hist-status-deployed').map((i, a) => $(a).parent()).map((i, a) => $(a).find('md-menu button:contains(Delete)')).each((i, it) => {
setTimeout(function() {
deleteDeployment(it)
}, (i + 1) * 2000)
})
Firebase finally implemented a solution for this.
It is now possible to set a limit of retained versions.
https://firebase.google.com/docs/hosting/deploying#set_limit_for_retained_versions
EDIT: previous link is outdated. Here is a new link that works:
https://firebase.google.com/docs/hosting/usage-quotas-pricing#control-storage-usage
This may be a bit brittle due to the selectors' reliance on current DOM structure and classes on the Hosting Dashboard, but it works for me!
NOTE: This script (if executed from the console) or bookmarklet will click and confirm delete on all of the rows in the current view. I'm fairly certain that even if you click delete on the current deployment it will not delete it.
Function for running in console:
let deleteAllHistory = () => {
let deleteBtns = document.querySelectorAll('.table-row-actions button.md-icon-button');
const deleteBtn = (pointer) => {
deleteBtns[pointer].click();
setTimeout(() => {
document.querySelector('.md-open-menu-container.md-clickable md-menu-item:last-child button').click();
setTimeout(() => {
document.querySelector('.fb-dialog-actions .md-raised').click();
if(pointer < deleteBtns.length - 1) {
deleteBtn(pointer + 1);
}
}, 500);
}, 500);
};
deleteBtn(0);
};
Bookmarklet:
javascript:(function()%7Bvar%20deleteBtns%3Ddocument.querySelectorAll('.table-row-actions%20button.md-icon-button')%2CdeleteBtn%3Dfunction(a)%7BdeleteBtns%5Ba%5D.click()%2CsetTimeout(function()%7Bdocument.querySelector('.md-open-menu-container.md-clickable%20md-menu-item%3Alast-child%20button').click()%2CsetTimeout(function()%7Bdocument.querySelector('.fb-dialog-actions%20.md-raised').click()%2Ca%3CdeleteBtns.length-1%26%26deleteBtn(a%2B1)%7D%2C500)%7D%2C500)%7D%3BdeleteBtn(0)%7D)()
Nathan's option is great, but I have a quick-and-dirty method using AutoHotkey. Takes about a second per version to delete, so you can knock out a page in 10 seconds.
#a::
Click
MouseGetPos, xpos, ypos
MouseMove, xpos, ypos + 30
Sleep 300
Click
Sleep 400
Click 1456, 816
MouseMove, xpos, ypos + 82
return
#s::
Click
MouseGetPos, xpos, ypos
MouseMove, xpos, ypos - 820
return
You'll likely need to modify the exact pixel values for your screen, but this works perfectly on my 1920x1080.
Win + a is delete and move to the next entry, Win + s is move to the next page. Put your mouse on the first 3-dot menu and go for it!
On top of the release history table, click the tool bar and select "Version history settings". Set to desired amount and click save.This will auto delete older deployments.
I don't know it can help you or not but I can delete old deployments from "hosting" menu like this:
Delete or rollback old deployment
I am new to firebase and I am having a bit of a nightmare trying to adapt old code to what is now deprecated and what is not. I am trying to write a function which updates one "single" record in my datasource using the now approved $save()promise but it is doing some really strange stuff to my data source.
My function (should) enables you to modify a single record then update the posts json array. However, instead of doing this, it deletes the whole datasource on the firebase server and it is lucky that I am only working with testdata at this point because everything would be gone.
$scope.update = function() {
var fb = new Firebase("https://mysource.firebaseio.com/Articles/" + $scope.postToUpdate.$id);
var article = $firebaseObject(ref);
article.$save({
Title: $scope.postToUpdate.Title,
Body: $scope.postToUpdate.Body
}).then(function(ref) {
$('#editModal').modal('hide');
console.log($scope.postToUpdate);
}, function(error) {
console.log("Error:", error);
});
}
Funnily enough I then get a warning in the console "after" I click the button:
Storing data using array indices in Firebase can result in unexpected behavior. See https://www.firebase.com/docs/web/guide/understanding-data.html#section-arrays-in-firebase for more information. Also note that you probably wanted $firebaseArray and not $firebaseObject.
(No shit?) I am assuming here that $save() is not the right call, so what is the equivalent of $routeParams/$firebase $update()to do a simple binding of the modified data and my source? I have been spending hours on this and really don't know what is the right solution.
Unless there's additional code that you've left out, your article $firebaseObject should most likely use the fb variable you created just before it.
var article = $firebaseObject(fb);
Additionally, the way in which you're using $save() is incorrect. You need to modify the properties on the $firebaseObject directly and then call $save() with no arguments. See the docs for more.
article.Title = $scope.postToUpdate.Title;
article.Body = $scope.postToUpdate.Body;
article.$save().then(...
I am using Meteor 4.2 (Windows) and I am always getting the "update failed: 403 -- Access denied. Can't replace document in restricted collection" when I am trying to update an object in my collection. Strangely I had no problem inserting new ones, only updates are failing.
I tried to "allow" everything on my collection:
Maps.allow({
insert: function () { return true; },
update: function () { return true; },
remove: function () { return true; },
fetch: function () { return true; }
});
But still, this update fails:
Maps.update({
_id: Session.get('current_map')
}, {
name: $('#newMapName').val()
});
Is there something else I can check? Or maybe my code is wrong? Last time I played with my project was with a previous version of Meteor (< 4.0).
Thanks for your help.
PS: Just for information, when I do this update, the local collection is updated, I can see the changes in the UI. Then very quickly it is reverted along with the error message, as the changes has been rejected by the server-side.
Alright, the syntax was actually incorrect. I don't understand really why as it was working well before, but anyway, here is the code that works fine:
Maps.update({
Session.get('current_map')
}, {
$set: {
name: $('#newMapName').val()
}
});
It seems like it must be related to what you're storing in the 'current_map' session variable. If it's a db object, then it probably looks like {_id:<mongo id here>} which would make the update finder work properly.
I ran into the same issues, and found the following to work
Blocks.update {_id:block_id}, {$set: params}
where params is a hash of all the bits i'd like to update and block_id is the mongo object id of the Block i'm trying to update.
Your note about the client side update (which flashes the update and then reverts) is expected behavior. If you check out their docs under the Data and Security section:
Meteor has a cute trick, though. When a client issues a write to the server, it also updates its local cache immediately, without waiting for the server's response. This means the screen will redraw right away. If the server accepted the update — what ought to happen most of the time in a properly behaving client — then the client got a jump on the change and didn't have to wait for the round trip to update its own screen. If the server rejects the change, Meteor patches up the client's cache with the server's result.