updating an existing item in an azure mobile service database - javascript

I have a server side script which is trying to update an already existing row with new data that is calculated in the script. When there isn't a row there it adds to the table fine.However when I try to update the row I get an error in my application that tells me that an item with that id already exists.
Below is the code I am using for the script. Any tips would be much appreciated.
function insert(item, user, request) {
var table = tables.getTable('Reviews');
table.where({
text: item.id
}).read({
success: upsertItem
});
function upsertItem(existingItems) {
if (existingItems.length == 0) {
item.numReviews = 1;
item.rating = item.reviews;
request.execute();
} else {
item.id = existingItems[0].id;
item.numReviews = existingItems[0].numReviews + 1;
var average = existingItems[0].reviews / item.numReviews;
item.reviews = existingItems[0].reviews + item.reviews;
item.rating = average;
table.update(item, {
success: function(updatedItem) {
request.respond(200, updatedItem)
}
});
}
}
}

For your initial query, you want to query by the id field:
table.where({
id: item.id
}).read({
success: upsertItem
});
Edit: further clarification
Your query object, {text: item.id} is effectively turned into the SQL query, select * from Reviews where text = item.id where item is the POST body. So your code sample is searching for Reviews where the text column has an id value in it. It doesn't find any, so the upsert() callback function if statement evaluates to true because existingItems is empty, and tries to insert the item by calling request.execute().
With the change I suggested, using {id: item.id}, becomes a query like
select * from Reviews where id = item.id so it will search for the Review with a matching id value in the id column.

Related

how do i SELECT then parse SQLite row values to assign as variables using Cordova-sqlite-storage plugin

I have a multipage app in Cordova using a (for now local only) SQLite database. All I am wanting to do initially is to use a single row to store 2 different values which I would like to occasionally SELECT, modify, then UPDATE the row with again. I think I am able to SELECT a specific a row but I can't figure out how to parse the two values in the row ready for assigning to variables.
I am using the cordova-sqlite-storage plugin.
var myDB;
/first create/open the database
myDB = window.sqlitePlugin.openDatabase({ name: "mySQLite.db", location: 'default' });
//create table and populate
myDB.transaction(function (tx) {
tx.executeSql('CREATE TABLE IF NOT EXISTS mcappDB (id text primary key, val1 integer, val2 integer)');
tx.executeSql('INSERT INTO mcappDB VALUES (?,?,?)', ['SessionNums', 12, 15]);
}, function (error) {
alert('Transaction ERROR: ' + error.message);
}, function () {
alert('Table created and populated');
});
//SELECT row and parse (and needing to store parsed data as global variables)
myDB.transaction(function (tx) {
tx.executeSql('SELECT * FROM mcappDB WHERE id="SessionNums"', [],
function (tx, rs) {
alert('Whats in here? ' + rs);
},
function (tx, error) {
alert('select ERROR: ' + error.message);
});
});
Presently, rs just returns as [object Object] and I am unable to parse it. I have tried using rs.toString(0), rs.getString(0), rs.column.item(1), rs(1), etc to no avail.
I in fact began with WHERE id=SessionNums, i.e. no quotes on the row id, but oddly this returned an error with no such columns: SessionNums, tho I thought using the WHERE id= command as such was for fetching row information?! e.g. http://zetcode.com/db/sqlite/select/
Any and all help would be much appreciated.
Cheers, Chris.
First of all, make sure that you have inserted the record before you read it with promises.
Separate insert function and read function and then use this:
$.when(insertFunc()).done(readFunc());
After that you can parse the results as follow:
if (rs.rows.length > 0) {
for (var i = 0; i < rs.rows.length; i++) {
console.log("val1: " + rs.rows.item(i).val1 + "\n" + "val2: " + rs.rows.item(i).val2);
}
}
Best regards,
#BernaAsis

vuejs - Caching searchresults of table based on multiple filters

I'm using vuejs for this project, but this problem is not necessarily connected - but if there is a vue-way, I would prefer that.
I'm building a table, that enables the user to have per-column-filters (in this case simple inputs). The columns are dynamic, so is the amount of data (thousands of rows, but less than 100.000 entries).
// example data
var columns = ['id', 'title', 'date', 'colour']
var data = [{ id: 1, title: 'Testentry 1', date: '2017-02-21T07:10:55.124Z', colour: 'green'}]
Here is the problem: I'm iterating over the columns, checking if a search-input exists, and if so, I try to filter the data based on the searchquery. In case of the ID, the time complexity is O(n). If I know search for a title additionally, I can reuse the result of the first searchquery, dramatically reducing the amount of data has to be looked at.
The searchqueries are stored in an object search, and the filtered data is a computed property, that gets updated whenever search changes. The way how that works though is, that if I change the searchquery for title, it would re-evaluate the searchquery even for the ID, although the searchquery for that didn't change.
This would require some kind of caching of data filtered for each column. And only the proceeding columns need to be queried upon.
edit: added code for the filtering:
filteredRows () {
var rows = this.data
for (var i = 0; i < this.columns.length; i++) {
var column = this.columns[i].name
var search = this.tSearch[column]
if (!search && search.length === 0) continue
console.log(column + ': ' + ' (' + search + ') -> ' + rows.length)
rows = _.filter(rows, (row) => {
var value = '' + row[column]
value.search(search) > -1
})
}
return rows
}
Just a suggestion, but did you try to use a watcher to get old and new value of input.
data: function() {
return {
propertyToWatch: 'something'
}
},
computed: {
...
},
watch: {
'propertyToWatch': function (val, oldVal) {
console.log(oldVal); // logs old value
console.log(val); // logs current value
// here you can call a function and send both of these args and detect diff
}
},
....

Searching nested object with Elastic Search and Firebase

Following the Flashlight GitHub example by Firebase.com, I got it to work as instructed to deploy on Heroku - but the way my data is structured, I think there might be a better way?
My data structure looks like this:
(root)pages
-->Firebase Unique ID
---->chat
---->content
------>Firebase Unique ID
-------->title
-------->description
-------->filter = article
---------->tags
------------tag 1
------------tag 2
I only want Elastic Search to return results based on matching the tags or the filter = article, but I get everything from pages down (all the chat, all the content regardless if it matched the result, but not content from other pages, etc...)
The path in config.js for the flashlight code is simply:
exports.paths = [
{
path: "pages",
index: "firebase",
type: "pages"
},
{
path: "event_entry",
index: "firebase",
type: "events"
}
];
I'm still early enough in development that I can change the structure of the data; I thought about:
(root) content
-->Firebase Unique ID
---->title
---->description
---->filter = article
And then simply storing the Firebase Unique ID in the pages object somewhere?
As it stands right now, I'm parsing the result as so to check the tags and only show what is actually tagged with what I searched for and it's just... ugly...
function showResults(snap) {
if( snap.val() === null ) { return; } // wait until we get data
var dat = snap.val();
var out = '';
$.each(dat["hits"]["0"]["_source"]["content"], function(i, v) {
for(var k in v.tags)
{
if(v['tags'][k]['text'] == $scope.search)
{
out += v.title + ": " + i + "<br>";
console.log(i);
}
}
});
$("#results").text(out);
}

Assigning attributes from an array

I am trying to build a form based off of column names I get from a PHP script, through AJAX, and a pre-defined array of column details. I am hoping to assign these pre-defined attributes to the incoming columns and build a form. For example, if I ever get the column "UserName" I want to to always be an < input >
The template
var template = {
UserName : {
label: "User Name:",
type: "input"
}
UserId : {
label: "User Id:",
type: "text"
}
}
Incoming JSON array from AJAX request
{"UserName":"bob", "UserId":"1"}
Now I need to somehow 'match' these. I myself am not sure exactly what to do here.
$.each(data, function(i,e){
// if index (such as UserName) is found in template array, maybe add the attributes to it?
});
For your case, use obj.hasOwnProperty(key) to test if it exists, concatenate a string and use a ternary assignment to build a input element. You could also use an if statement if you wished.
var $html = '';
$.each(data, function(idx,v){
$html += template.hasOwnProperty(idx)? '<input type="'+template[idx]['type']+'" name="'+idx+'"/>': '';
});
console.log($html);
Here's your jsFiddle
An alternative (and perhaps wordier) solution including label processing might be shown in this jsFiddle. The high level is based on the following code:
$(function () {
var template = {
UserName: {
label: "User Name:",
type: "input"
},
UserId: {
label: "User Id:",
type: "text"
}
};
var data = {
"UserName": "bob",
"UserId": "1"
};
$.each(data, function (key, value) {
if (template[key] != undefined) {
$("#here").append($("<span>" + template[key].label + "</span>"));
$("#here").append($("<input type=\"" + template[key].type + "\">"));
$("#here").append($("<br>"));
}
});
});

Implementing MongoDB 2.4's full text search in a Meteor app

I'm looking into adding full text search to a Meteor app. I know MongoDB now supports this feature, but I have a few questions about the implementation:
What's the best way to enable the text search feature (textSearchEnabled=true) in a Meteor app?
Is there a way to add an index (db.collection.ensureIndex()) from within your app?
How can you run a Mongo command (i.e. db.quotes.runCommand( "text", { search: "TOMORROW" } )) from within a Meteor app?
Since my goal is to add search to Telescope, I'm searching for a "plug-and-play" implementation that requires minimal command line magic and could even work on Heroku or *.meteor.com.
The simplest way without editing any Meteor code is to use your own mongodb. Your mongodb.conf should look something like this (on Arch Linux it is found at /etc/mongodb.conf)
bind_ip = 127.0.0.1
quiet = true
dbpath = /var/lib/mongodb
logpath = /var/log/mongodb/mongod.log
logappend = true
setParameter = textSearchEnabled=true
The key line is setParameter = textSearchEnabled=true, which, as it states, enables text search.
Start mongod up
Tell meteor to use your mongod not its own by specifying the MONGO_URL environmental variable.
MONGO_URL="mongodb://localhost:27017/meteor" meteor
Now say you have collection called Dinosaurs declared say in collections/dinosaurs.js
Dinosaurs = new Meteor.Collection('dinosaurs');
To create an text index for the collection create a file server/indexes.js
Meteor.startUp(function () {
search_index_name = 'whatever_you_want_to_call_it_less_than_128_characters'
// Remove old indexes as you can only have one text index and if you add
// more fields to your index then you will need to recreate it.
Dinosaurs._dropIndex(search_index_name);
Dinosaurs._ensureIndex({
species: 'text',
favouriteFood: 'text'
}, {
name: search_index_name
});
});
Then you can expose the search through a Meteor.method, for example in the file server/lib/search_dinosaurs.js.
// Actual text search function
_searchDinosaurs = function (searchText) {
var Future = Npm.require('fibers/future');
var future = new Future();
Meteor._RemoteCollectionDriver.mongo.db.executeDbCommand({
text: 'dinosaurs',
search: searchText,
project: {
id: 1 // Only take the ids
}
}
, function(error, results) {
if (results && results.documents[0].ok === 1) {
future.ret(results.documents[0].results);
}
else {
future.ret('');
}
});
return future.wait();
};
// Helper that extracts the ids from the search results
searchDinosaurs = function (searchText) {
if (searchText && searchText !== '') {
var searchResults = _searchEnquiries(searchText);
var ids = [];
for (var i = 0; i < searchResults.length; i++) {
ids.push(searchResults[i].obj._id);
}
return ids;
}
};
Then you can publish only documents that have been searched for in 'server/publications.js'
Meteor.publish('dinosaurs', function(searchText) {
var doc = {};
var dinosaurIds = searchDinosaurs(searchText);
if (dinosaurIds) {
doc._id = {
$in: dinosaurIds
};
}
return Dinosaurs.find(doc);
});
And the client side subscription would look something like this in client/main.js
Meteor.subscribe('dinosaurs', Session.get('searchQuery'));
Props to Timo Brinkmann whose musiccrawler project was the source of most this knowledge.
To create a text index and try to add like this I hope so it will be useful if there is still problem comment
From docs.mongodb.org:
Append scalar index fields to a text index, as in the following
example which specifies an ascending index key on username:
db.collection.ensureIndex( { comments: "text",
username: 1 } )
Warning You cannot include multi-key index field or geospatial index
field.
Use the project option in the text to return only the fields in the
index, as in the following:
db.quotes.runCommand( "text", { search: "tomorrow",
project: { username: 1,
_id: 0
}
}
)
Note: By default, the _id field is included in the result set. Since the example index did not include the _id field, you must
explicitly exclude the field in the project document.

Categories

Resources