FaunaDB: How to create index for arbitrary length-array field - faunadb

Is there a way to create an index for an array property of a document, so that I can Match the document based on any value in the array?
For example, assuming a document looks something like
{ data: { ips: ['192.168.1.1', '::ffff:c0a8:101'] } }
then I'd like to have an index documents_by_ip s.t. I can retrieve that document with either 192.168.1.1 or ::ffff:c0a8:101.

I was able to answer this question before even posting it. There are no extra steps required, just adding a field that is an array to the index terms will do exactly what I wanted to ~~~
CreateIndex('documents_by_id', { terms: [{ field: ['data', 'ips'] }] })

Related

Vue: Setting Data by matching route query

I'm attempting to set data fields provided by an array based on the Vue Router query. For example, when someone lands on my website using example.com/?location=texas, I want to set the location data by an array.
An example the array:
locations {
{
slug: "texas",
tagline: "Welcome to Texas",
}, {
slug: "california",
tagline: "Welcome to California",
}
}
I know this should be done using a computed property, however I am unable to get anything functioning. I've tried simple tests like if (this.slug.location === "texas"), and I cannot get the location data to populate. I would also like to provide default data in case there are no route matches.
Any help is extremely appreciated!
Edit:
I can accomplish this in a very manual way. Right now, I'm setting the query in data by the following:
slug: this.$route.query.location
I can display specific text by doing something like:
h3(v-if="slug === 'texas'") This will show for texas
h3(v-else-if="slug === 'california'") This will show for California
h3(v-else) This is default
The issue with this approach is there are various elements I need to customize depending on the slug. Is there any way I can create an array, and move whichever array matches a key in an array to the data??
You should be able to access a query param using the following (link to Vue Router documentation):
this.$route.query.location
So based on what you listed I would do something like...
export default {
computed: {
displayBasedOnLocationQueryParam() {
switch(this.$route.query.location) {
case 'texas':
return 'Welcome to Texas'
default:
return 'hello there, generic person'
}
}
}
}
Note that I'm not using your array explicitly there. The switch statement can be the sole source of that logic, if need be.

How to make jqGrid dynamically populate options list based on row data

I am using jQrid version 3.8.1 with inline editing and each row in the grid has several dropdown lists to populate. When the user edits the row, I need to do an AJAX query to get the values for each of these lists. I've seen this post regarding how to do that. It appears that the dataUrl and buildSelect features are the standard answer here. There are a few issues I can't figure out though:
The row the user is editing has a value that must be passed into the dataUrl value. For example, say each row contains a field called "SpecialValue" and that for row 1, SpecialValue = 100. The dataUrl field for row 1 would be "http://my.services.com?SpecialValue=100". How do I do that?
Each row in the grid has about 10 select boxes that need to be populated. For efficiency reasons, I don't want to make 10 separate AJAX calls. It would be much better to make one call to get all the data, split it up, and fill each select box accordingly. Is that possible? I tried doing this inside onSelectRow but the grid ended up ignoring the values I put in there (I'm guessing do the ordering of the events that fire when you edit a row).
Edit:
After reading Oleg's answers and working on it more, it's clear to me that using dataUrl and buildSelect are not going to work well for me. The version of jqGrid I'm using doesn't support using dataUrl the way I would need. And even if it did I don't want to send multiple separate requests for each dropdown list.
I've decided to do one request when gridComplete fires to pull all the data needed for all dropdown lists into a single JSON structure. Then when the user selects a row to do inline editing, I will populate each list in the row from that JSON structure (the code below uses the getSelectValuesFromJSON() function for that--I don't give its definition but you can imaging it looks through the structure and gets an appropriate list of values to but in the list box).
I have a few candidate solutions but I'm not 100% happy with either one.
Solution 1:
Inside onSelectRow, I call editRow overriding the on oneditfunc to get the data out of the grid that I need. Assume that the value in Field1 is required to get the values to be put into the list in Field2.
onSelectRow: function (index, status, e) {
jQuery('#my_grid').jqGrid('editRow', index, true, function(rowId) {
var f1Val = $('#my_grid').jqGrid('getCell', index, 'Field1');
var selectVals = getSelectValuesFromJSON(f1Val); //gets data out of previously loaded JSON structure
var select = $('#my_grid').find('tr[id="' + index + '"] td[aria-describedby="my_grid_Field2"] select');
_.each(selectVals, function(selectVal) {
$(select).append($("<option></option>").attr("value", selectVal).text(selectVal));
});
});
}
This works but I'm hesitant about the line
var select = $('#my_grid').find('tr[id="' + index + '"] td[aria-describedby="my_grid_Field2"] select');
which relies on this aria-describedby attribute that I don't know much about. Seems hacky and brittle.
Solution 2:
Make use of beforeSelectRow to dynamically change the model of the Field2 column when the user selects a row.
beforeSelectRow: function(index, e) {
var f1Val = getGridCellValue('#my_grid', index, 'Field1');
var values = getSelectValuesFromJSON(f1Val); //gets data out of previously loaded JSON structure
var valStr = "";
_.each(values, function(value) {
valStr += value + ":" + value + ";"
});
jQuery('#grid_pipes').setColProp('Field2', { editoptions: { value: valStr } });
return true;
}
This also works but I'm not sure about whether or not this is really a good idea. Is it valid to dynamically change the model of a column like that? What if the user has several rows selected at the same time? Isn't there only one model for a column? What would that mean?
To answer some of Oleg's questions, the dataType has been set to a function that uses $.ajax to post data to the server. I think I read that's not the recommended approach anymore. I inherited this code so I'm not sure why it was done that way but it probably won't change unless there is a really compelling reason.
The loadonce boolean is not specified so I guess that means it defaults to false.
Here is an abbreviated version of the column model (nothing terribly out of the ordinary):
colModel: [
{ name: 'PK', index: 'PK', hidden: true, editable: true, sortable: true, search: true },
{ name: 'Field1', index: 'Field1', hidden: true, editable: true, sortable: true, search: true },
{ name: 'Field2', index: 'Field2', sortable: false, editable: true, search: false, edittype: "select", editoptions: {} },
{ name: 'Field3', index: 'Field3', sortable: false, editable: true, search: false, edittype: "select", editoptions: {} },
...
]
You don't wrote which version of jqGrid you use currently, but dataUrl can be defined as callback function with (rowid, value, name) parameters, which have to return the URL which you can build dynamically based on the information. The feature exist starting with v4.5.3 (see the line). You can use getCell, getRowData or getLocalRow inside of the callback to get the data from another columns of the row. Thus you can solve your first problem relatively easy.
You second question seems to me absolutely independent from the first one. It's better to separate such questions in different posts to allow the searching engine better to index the information and so to help other people to find it.
There are no simple way how to solve the second problem, but one can sure suggest a solution, but one have to know much more details what you do and how you do. How you start inline editing (do you use inlineNav, formatter: "actions" or you call editRow directly)? Which version of jqGrid (till version 4.7), free jqGrid or Guriddo jqGrid JS you use? How the columns with selects are defined in colModel? Which datatype you use and whether loadonce: true you use? I recommend you to post separate question with the information.
UPDATE: If you have to use old version of jqGrid then you can't generate dataUrl full dynamically, but because you need to add only SpecialValue=100" part to the URL you can follow the trick which I described in many my old answers (the first one was probably here, but the choice on property names which asked the user could be misunderstood). You can use ajaxSelectOptions.data which will define the data parameters of jQuery.ajax request. The problem only that you can define only one ajaxSelectOptions.data property. So you can add the following jqGrid option:
ajaxSelectOptions: {
data: {
SpecialValue: function () {
var rowid = $myGrid.jqGrid("getGridParam", "selrow");
return $myGrid.jqGrid("getCell", rowid, "SpecialValue");
}
}
}
($myGrid is something like $("#grid"))
UPDATED: You used unknown functions getSelectValuesFromJSON, getLookupValuesFromJSON in the updated part of your question. Both of there seems to use synchronous Ajax request which is not good. Moreover you set editoptions.value for only one Field2 instead of setting all selects.
onSelectRow: function (rowid) {
var $myGrid = $(this);
$.ajax({
url: "someUrl",
dataType: "json";
data: {
specialValue: $myGrid.jqGrid("getCell", rowid, "Field1")
},
success: function (data) {
// for example response data have format:
// { "Field2": ["v1", "v2", ...], "Field3": ["v3", "v4", ...] }
var filed, str;
for (filed in data) {
if (data.hasOwnProperty(filed)) {
str = $.map(data[filed], function (item) {
return item + ":" + item
}).join(";");
$myGrid.jqGrid("setColProp", filed, {
editoptions: {
value: str
}
});
}
}
$myGrid.jqGrid("editRow", rowid, true);
}
});
}
Nevertheless the "Solution 2" is more close to what I would recommend you. It's not really important whether to use onSelectRow or beforeSelectRow. You can make asynchronous Ajax request to the server which returns information for all select which you need. After you get the response from the server (inside of success callback) you can set editoptions.value for all selects and only then you can start editRow. In the way you will be sure that editing of the line will use row specific options in all select.
Some additional remarks. I recommend you to verify gridview: true option in the grid. Additionally I suspect that you fill the grid in not full correct way because you have hidden PK column and you use index instead of rowid as the first parameter of beforeSelectRow and onSelectRow. It's very important to understand that the current implementation of jqGrid always assign id attribute on every row (<tr> element) of the grid. So you have to provide id information in every item of input data. If you want to display the id information to the user (and so to have column in colModel with the primary key) then you should just include key: true property in the column definition. For example you can add key: true to the definition of PK column and so you will have rowid (or index in your case) with the same value like PK. It simplify many parts of code. For example jqGrid send id parameter in the editing request to the server. It's practical to have PK in the request. Moreover if you use repeatitems: false format of jsonReader the you can include id: "PK" in the jsonReader instead of having hidden PK column. It informs jqGrid to get rowid from PK. jqGrid will save PK in id attribute of <tr> and you will don't need to have additional <td style="display:none"> with the same information in the grid.
The last remark. I would strictly recommend you to update the retro version jqGrid 3.8.1 to some more recent version, for example to free jqGrid. Even if you would use no features (like Font Awesome for example) you will have performance advantages, and the look of modern web browsers will looks much better. You should understand the jqGrid 3.8.1 was tested with old (and slow jQuery 1.4.2). The version used with Internet Explorer 8 as the latest IE version (IE9 was published later in March 2011) and it's more oriented on IE6/IE7. The look in modern Chrome/Firefox/Safari can be bad. Is it what you want?

Dojo store query with wildcard

I'm using a Dojo memory store (dojo/store/Memory). I would like to retrieve items based on a wildcard query but the query method doesn't seem to support wildcards. i.e. given the following items:
{ id: "apple", details: "fruit" }
{ id: "applemac", details: "computer" }
store.query({ id: "apple" }) returns the first row as expected, but store.query({ id: "apple*" }) returns nothing.
Does anyone know if it's possible to use wildcards and if so, how?
Thanks
You can use a RegExp object to do wildcard queries
store.query({id:new RegExp("apple*")})
Here's a JSFiddle

how do we read a csv file and display the same in dojo?

i want to write a dojo code where upon a button click i want to read a .csv file and display the .csv file in a datagrid using Dojo. Can anyone please help me with this?
Your best try is to retrieve the data using the dojo/request/xhr module, with it you can retrieve an external CSV file. For example:
require(["dojo/request/xhr"], function(xhr) {
xhr.get("myfile.csv", {
handleAs: "text"
}).then(function(data) {
// Use data
});
});
Well, now you have the data as a string in your data parameter, what you now need to do is parse that string. The easiest way is to split your string on each enter, for example:
var lines = data.split(/\r?\n/);
The \r is optional (depends on the system you're using), but now you have each line seperated in an array element in lines. The next step is to retrieve each seperate value, for example by doing:
require(["dojo/_base/array"], function(array) {
/** Rest of code */
array.forEach(lines, function(line) {
var cells = line.split(',');
});
});
Then you have your data splitted by each comma. The next step is that you have to change it to a format that the dojox/grid/DataGrid can read. This means that you will probably convert the first line of your CSV content to your headers (if they contain headers) and the rest of the data to objects (in stead of arrays of strings).
You can get the first line with:
var headers = lines[0].split(',');
And the rest of the data with:
var otherData = lines.splice(1);
Now you should carefully read the documentation #MiBrock gave you, and with it you can transform the simple array of strings to the correct format.
The headers should become an array of objects like this:
[{ name: "display name", field: "field name" }, { /** other objects */ }]
I did that by doing:
array.map(headers, function(header) {
return {
field: header,
name: header
};
});
This will actually convert [ "a", "b" ] to:
[{ field: "a", name: "a" }, { field: "b", name: "b" }]
Now you need to convert all other lines to objects containing a field with name a and a field with name b, you can do that using:
array.map(otherData, function(line) {
var cells = line.split(','), obj = {};
array.forEach(cells, function(cell, idx) {
obj[headers[idx]] = cell;
});
return obj:
});
This will actually retrieve the fieldname by retrieving the corresponding header value and output it as a single object.
Now you can put it in a grid, look at #MiBrock's answer for more details about how to do that. The final result would look a bit like this JSFiddle.
Note: Next time you encounter a problem you can't solve, handle the parts you actually can solve first and then ask a question about the other parts. I mean, it's hard to believe that you can actually not solve any of this by yourself. You should try and learn it by yourself first.
The dojo-smore project includes a CSV object store that loads data from CSV into an in-memory store which can then be used with any component that supports object stores, like dgrid. You shouldn’t try to do it yourself, like Dimitri M suggested, and you shouldn’t use the dojox grids, which are deprecated.
You can use dojox.data.CsvStore to read a CSV store and use it in a data grid.
Have a look here : http://dojotoolkit.org/reference-guide/1.8/dojox/grid/index.html#dojox-grid-index
and here: http://dojotoolkit.org/documentation/tutorials/1.9/populating_datagrid/
This should help you to start with your Programming.
If you need further help, show us what you have tried to solve the Problem by posting your code and we'll be glad to help you.
Regards, Miriam

Limit couchdb-lucene results by key / specific field? map?

I have a pretty straight-forward question.
I am using couchdb-lucene to search the full text of my documents.
My documents each have the following fields:
_id
_rev
docID (the unique ID of the document from our system)
title (title of the document)
content (body of the document)
userID (the user that owns the document)
My design document looks likes this:
{
"_id": "_design/lucene",
"_rev": "10-770b7044393e067b7024a896ccf3c502",
"fulltext": {
"by_all": {
"index": "function(doc) { var ret=new Document(); ret.add(doc.title); ret.add(doc.content); return ret }"
},
"by_title": {
"index": "function(doc) { var ret=new Document(); ret.add(doc.title); return ret }"
}
}
}
I couldn't figure out how to return the docID as part of the results, so I just made the ID equal to the docID for now, but I would like to understand how to return the docID since the design document above only returns the score and ID of the document. I would rather not have to set the ID to the same value as docID just to access it.
When I run a request such as:
localhost:5984/foo/_fti/_design/lucene/by_all?q=example~0.5f
I get back a collection of all documents where the title or content field contains "example", and that's great, but how can I search for "example" in the title and content fields of ONLY the documents that have a specific userID? How can I pass in and use that value?
I want to do something like this:
localhost:5984/foo/_fti/_design/lucene/by_all?q=example~0.5f&userId=123
When I do: localhost:5984/foo/_fti/_design/lucene/by_all?q=example~0.5f it returns documents for all users, what do I need to do to limit the documents only to those belonging to a specific user? I don't want to search every document out of millions when only a few thousand are relevant to a specific user.
Thanks!
p.s. I know I can use a map in views: "map": "function(doc){ emit(doc._id, doc._rev)}"
Is this relevant? Is there some way to use the map within the couchdb-lucene results? I couldn't figure out how to specify which value to use at the key for the map, so it was returning the ID by default, how can the key be set to use a specific field? Maybe map isn't even the right track... I don't know what to do here, I'm very new to both CouchDB and Lucene and don't really quite understand it all yet.
Thanks again!
This seems straightforward but you'll need to change your index function.
function(doc) {
var ret=new Document();
ret.add(doc.title);
ret.add(doc.content});
ret.add(doc.userID, {"field":"userID"});
ret.add(doc.docID, {"field":"docID","store":"yes"});
return ret;
}
Query with;
localhost:5984/foo/_fti/_design/lucene/by_all?q=example%20AND%20userID:123
This will find all documents with 'example' in the title or the content as long as userID is equal to 123. Additionally, the docID value will be returned in the results.
HTH,
B.