loop through CouchDB fields in document (validate_doc_update) - javascript

I am trying to loop through the fields in a CouchDB document and check that the old version of the field and new version are the same (as part of my validate_doc_update). However, I would like to do the equivalent of a "foreach field in documents, check to make sure they are the same", instead of having to say something like
oldrev.document.field1 == newrev.document.field1, oldrev.document.field2 == newrev.document.field2,
blah blah. Is there a way
to do this with CouchDB fields, or do I have to specify the name of each field? It would be nice to not type them all in, and if we ever change the field names, to not have to come back in and tweak things.

A JS for in loop should suffice:
for (var key in newrev) {
if (newrev.hasOwnProperty(key) {
if (oldrev[key] === newrev[key]) {
// they are the same
}
}
}
There is one thing you'll need to be cautious of here, and that is that deleting/adding fields between revisions may be harder to validate.
I'm pretty sure Object.keys is available to SpiderMonkey, so you may need to use that to compare the number of keys between old and new.

The values passed as newDoc, and oldDoc parameters to validate_doc_update function are Javascript objects: you compare two documents as you compare any JS objects. There no "CouchDB field".
You can write custom code, or you can use a JS library like Underscore.js. You can include it as a CommonJS module. The only problem is the _rev field. My approach is to keep CouchDB metadata separate from document data, by putting the data in a data field. For example:
{ "_id": "ID", "_rev": "REV", "foo": "bar", "baz": [1, 2] }
becomes
{ "_id": "ID", "_rev": "REV", "data": { "foo": "bar", "baz": [1, 2] } }
Then the comparison can be done with
function(newDoc, oldDoc) {
var _ = require("underscore");
if (!_.isEqual(newDoc.data, oldDoc.data)) {
// something changed...
}
}

Related

How to pass an array of objects through a query string according to REST?

What is the best practice to pass an array of objects throught query string in REST style?
For example, the array:
examples[] = [
{
name: "foo",
value: "1"
},
{
name: "bar",
value: "2"
}
]
I thought about it:
/items?examples[0][name]=foo&examples[0][value]=1&examples[1}[name]=bar&examples[1][value]=2
Are there other ways to do this?
Upd:
I need readable URL to show it to the user in the address field. It should display state of some filters in the table, I'm not sending it to the backend.
Since you're parsing this manually in JS, you could keep the structure you have and just write a parsing function
var items = {};
location.search.split("?")[1].split("&").map((q) => {
var [token, value] = q.split("="),
[idx, key] = /\[([0-9+])\]\[(\w+)\]/g.exec(token).slice(1, 3);
if (!items[idx]){
items[idx] = {};
}
items[idx][key] = value;
})
This will yield you something with a structure like
{
"0": {
"key1": "data"
"key2": "data:
},
"1": {
"key1": "data"
"key2": "data"
}
}
If you need it to end up an array, it would be pretty easy to convert, but keeping it as an object with numeric strings for keys will prevent an error if it's not sequential.
Also, note there's no error checking or anything here, so if you're going to have query string params that aren't in that format, you'll want to test for that and handle them differently.
You shouldn't take care about how pass data for a backend, Angular do it for you.
About your example, you probably want to update or save several item. So it's not into the url that you will pass your data but into the Request Body :
this.httpService.post(yourUrl, examples, yourHttpOptions).subscribe( (response) => {
// you manage your response data
});
REST does not care how you encode information into your identifiers. You can use any scheme you want, so long as it is consistent with the production rules defined by RFC 3986.
REST cares a little bit about how you share information about creating URI, in the sense that that information should be shared in some readily standardizable form, like an HTML form, or a URI Template.
We don't, to my knowledge, have a "readily standardizable form" that describes how to transform a json array to a query string.
But... REST does allow code on demand; embedding, for example, a bunch of java script into a resource where that javascript knows how to encode the json into the URI... that is in bounds, so long as you have the code on demand itself referenced in a readily standardizable way (like we have with HTML and script tags).
In practice? urlencode the json representation and put it onto the query string directly. That will get you through until you start to discover the real requirements that your URI design needs to support (requirements like: operators needing to be able to understand the access logs).

Algolia search on nested objects in a record - multiple facetFilters in one object

I’m migrating from Mongo to Firebase with Algolia on top to provide the search. But hitting a snag coming up with a comparable way to search in individual elements of a record.
I have an object that stores when a room is available: from and to. Each record can have many individual from/to combos (see the sample below with 2). I want to be able to run a search something like:
roomavailable.from <= 1522195200 AND roomavailable.to >=1522900799
But only have the query search a match within each element, not any facet in all elements. An element query in Mongo works like that. But if I run that query on the record listed below, it will return the record, because the two roomavailable objects satisfy the .from and .to query. I think.
Is there a way to ensure the search is looking only at matching a pair of .from and .to in an individual object/element?
Below is the pertinent part of the record stored in Algolia so you can see the structure.
"roomavailable": [
{
"_id": "rJbdWvY9M",
"from": 1522195200,
"to": 1522799999
},
{
"_id": "r1H_-vKqz",
"from": 1523923200,
"to": 1524268799
}
],
And here is the Mongo (mongoose) equivalent where its searching inside individual elements (this works):
$elemMatch: {
from: {
$lte: moment(dateArray[0]).utc().startOf('day').format()
},
to: {
$gte: moment(dateArray[1]).utc().endOf('day').format()
}
}
I have also tried this query but it seems to still match either the .from AND .to but in any of the the individual roomavailable elements:
index.search({
query: '',
filters: filters,
facetFilters: [roomavailable.from: 1522195200, roomavailable.to: 1524268799],
attributesToRetrieve: [
"roomavailable",
],
restrictHighlightAndSnippetArrays: true
})
I found a couple posts on Algolia discussing using 1 bracket vs. 2 brackets in the facetFilters. I've tried both. Neither work.
Any suggestions would be awesome. Thanks!
Edit: See discussion on Algolia Discourse:
https://discourse.algolia.com/t/how-to-match-multiple-attributes-in-nested-object-with-numericfilters/4887/8
Hi #kanec, thanks for clarifying your question!
Indeed what #Alefort suggested (using roomavailable in a separate index) would be the easiest option since the query I mentioned above will definitely return the results you want. This will mean that you'll have to query the room availability index separately in order to get which IDs are available, so you'll have to use multiple-queries:
https://www.algolia.com/doc/api-reference/api-methods/multiple-queries/
That said, I asked our core API team to see if there's a more reasonable way to approach this issue, but I fear that this is a filter limit due to performance reasons with arrays. You could transform your data structure in the following and index your rooms as an object instead:
[
{
"roomavailable": {
"0": {
"_id": "rJbdWvY9M",
"from": 1522195200,
"to": 1522799999
},
"1": {
"_id": "r1H_-vKqz",
"from": 1523923200,
"to": 1524268799
}
}
}
]
So you can apply the following filter:
{
"filters": "roomavailable.0.from <= 1522195200 AND roomavailable.0.to >= 1522799999 AND roomavailable.1.from <= 1522195200 AND roomavailable.1.to >=1522900799"
}
The downside of this is that you'll need to know the length of roomavailable in order to build the search query on the front-end (you can do so at indexing time by adding a roomavailable_count property) and also this will probably will be less performant with a considerable number of rooms per item; in this case, switching to a dedicated index makes totally sense for the following reasons:
If in your backend you frequently update available rooms you won't impact the other indices' build time
Filters will perform better (as explained above)
Indexing strategy will be simpler to handle
Let me know what you think about this and if it helps you out.

parsing json without knowing the identifiers in javascript

I have a JSON payload from a REST service that looks something like this:
var jsonify = JSON.stringify(theReturnedData);
console.log(jsonify) =
{
"f-012839": {
"name": "Bob",
"email": "asdf#gmail.com"
}
}
How do I access, for example, the email value without knowing what "f-012839" is?
Here is what I have tried so far without success:
var name = jsonify[0].name;
var name = jsonify.name;
The "f-012839" value is dynamic and I won't know what it is beforehand. It'd be nice if I could get to the "name" and "email" elements without having to know what the "f-012839" key would be. Or, is it possible to take a subset of the returned JSON, so that instead of having the above value, it could be something like this:
{
"name": "Bob",
"email": "asdf#gmail.com"
}
If that's possible, I should be able to get any of those values by simply doing the below, right?
var name = jsonify.name;
Any help would be greatly appreciated. Thanks SO!
for(var key in theReturnedData) {
theReturnedData[key] // This is the object you want access to
}
Update Also make sure to implement a check for each key. You need to filter out the properties that could be inherited from the objects Prototype (lots of frameworks add custom properties to object Prototypes. You can check that through Object.hasOwnProperty(property_name), so basically use this loop:
for(var key in theReturnedData) {
if(!theReturnedData.hasOwnProperty(key)) continue;
theReturnedData[key]
}
for(field in JSON.parse(jsonify)) {
firstObject = jsonify[field];
console.log(firstObject.name);
console.log(firstObject.email);
}

How to document JavaScript/CoffeeScript data structures

I am looking for a descriptive way to document the used data structures in my JavaScript application. I find it hard to get this done due to the dynamic character of JavaScript.
For instance, what could be a good way to tell, that a used variable distance is a two-dimensional array with length i and j and stores numbers between -1 and MAX_INT. I could think of something like this:
distance[i][j] = -1 <= n <= MAX_INT
What about an object which is used as a map/dictionary for certain data types, what about a two-dimensional array where the first element of an array defines other data then the rest, etc.
Of course, it is always possible to document these things in a text, I just thought, maybe there is a well known and used way to do this in a semiformal way.
Although it's not too widely adopted (yet?), there is a draft standard for JSON schema. I'm just learning it myself but you could write a schema for your two-dimensional array (wrapped inside of an object) as:
{
"description":"Two dimensional array of numbers",
"type":"object",
"properties":{
"two-d-array":{
"description":"columns",
"type":"array",
"items":{
"description":"rows",
"type":"array",
"items": {
"description":"values",
"type":"number",
"minimum":-1,
"maximum":Number.MAX_VALUE
}
}
}
}
}
or simply:
{
"type":"array",
"items":{
"type":"array",
"items": {
"type":"number",
"minimum":-1,
"maximum":Number.MAX_VALUE
}
}
}
There is no CoffeeScript implementation that I know of, but there is a list of several JavaScript validators here. I'm playing with the one that's written by the spec authors called (simply enough) json-schema and I like it well enough calling it from CoffeeScript.
What I tend to do in my JavaScript when I am replicating a lot of data models is to write out what their class definition would be in comments. I am not sure if this is what you meant with your question.
// JavaScript Class jsHomeLocation
// jsHomeLocation{
// string name
// string address
// }
var jsHomeLocation = {};
jsHomeLocation.name = "Travis";
jsHomeLocation.address = "California";
You could also use javascript objects to track the information of the example, a two-dimensional array
var distanceData = {};
distanceData.type = "two-dimensional array";
distanceData.length = i * j;
distanceData.min = -1;
distanceData.max = MAX_INT;

Querying/Searching for Values within JSON

For a web site I'm creating, I have to create a quote based on data provided as a JSON string from the server. I've been looking through this site (and various others) but still am unsure on the best way to query/search the data.
For example, I need to get the Area Name from the Area ID. I need to get the maximum age for an area and also the price for a given minimum/maximum age.
I also want to get an array of prices.
Is it best to create a Javascript object from the string using the eval method? Or should I be using jQuery.
Thanks for your help.
({"SkiPass":[{"Id":1,"Area":"Chamonix","Rates":[{"Id":1,"AgeMin":0,"AgeMax":2,"Price":2.5},{"Id":2,"AgeMin":3,"AgeMax":17,"Price":5.0},{"Id":3,"AgeMin":18,"AgeMax":30,"Price":6.2},{"Id":4,"AgeMin":31,"AgeMax":59,"Price":7.4}]},
{"Id":2,"Area":"Megeve","Rates":[{"Id":1,"AgeMin":0,"AgeMax":2,"Price":1},{"Id":2,"AgeMin":3,"AgeMax":17,"Price":2.0},{"Id":3,"AgeMin":18,"AgeMax":30,"Price":2.2},{"Id":4,"AgeMin":31,"AgeMax":59,"Price":4.4}]},
{"Id":3,"Area":"Verbier","Rates":[{"Id":1,"AgeMin":0,"AgeMax":2,"Price":1.5},{"Id":2,"AgeMin":3,"AgeMax":17,"Price":3.0},{"Id":3,"AgeMin":18,"AgeMax":30,"Price":4.2},{"Id":4,"AgeMin":31,"AgeMax":59,"Price":5.4}]}]})
Create a JavaScript object from the string, most definitely, but do it with legitimate JSON parsing facilities and not "eval()". You could use jQuery, but there are other solutions, such as the JSON tools available from json.org, which are small and simple.
Once it's a JavaScript object, well then your needs should guide you as to whether some query solution is necessary, or instead that it's just a simple matter of programming.
I think the best method is jLinq: http://hugoware.net/Projects/jLinq it's like doing a SQL query on JSON.
It doesn't needs jQuery.
I use it, and it's great.
Create the object from the JSON string using JSON.parse() or jQuery.parseJSON() if you are already using jQuery -- or just pass it as from the server side as JSON.
You can then iterate through the object to find the record you want. Or, you can use build your objects so that you can naturally grab data from them.
FloatLeft - as Dan points out, your task would be much easier if you could use XPath but there is no need to re-write your data in XML format. With DefiantJS (http://defiantjs.com) you can now query JSON structure with XPath expressions.
DefiantJS extends the global object JSON with the method "search", which enables XPath queries and returns an array with the matches (empty array if no matches were found). The returned array is equipped with aggregate functions as well; one of these "sortDesc".
Check out this working fiddle;
http://jsfiddle.net/hbi99/H3PR3/
var data = {
"SkiPass": [
...
{
"Id": 3,
"Area": "Verbier",
"Rates": [
{ "Id": 1, "AgeMin": 0, "AgeMax": 2, "Price": 1.5 },
{ "Id": 2, "AgeMin": 3, "AgeMax": 17, "Price": 3 },
{ "Id": 3, "AgeMin": 18, "AgeMax": 30, "Price": 4.2 },
{ "Id": 4, "AgeMin": 31, "AgeMax": 59, "Price": 5.4 }
]
}
]
},
res1 = JSON.search( data, '//SkiPass[Id=3]/Area' ),
res2 = JSON.search( data, '//*[Area and Id=3]/Rates' )
.sortDesc('AgeMax'); // <-- sorting descending by the value of "AgeMax"
document.getElementById('name').innerHTML = res1;
document.getElementById('max_age').innerHTML = res2[0].AgeMax;
document.getElementById('price').innerHTML = res2[0].Price;

Categories