ExtJS Search Datastore for value - search

How do I search a datastore for a specific record? I've tried find() and findBy(), but both return -1.
var index = clientStore.find('ClientID', '37');
I have a combo box with a list of clients. What I want is to be able to set a default value on that combo. I have the value setting correctly using setValue and I can even set the display value using setRawValue, but I can't seem to query the datastore based on the clientID and get the company name to use in setRawValue.
Does that make sense?
Here's the datastore code in response to the questions below (sorry it wouldn't let me paste it there)
var frmClientStore = new Ext.data.Store({
id: 'frmClientStore',
proxy: new Ext.data.HttpProxy({
url: 'url here',
method: 'POST'
}),
reader: new Ext.data.JsonReader({
root: 'rows',
id: 'recordID'
},[
{name: 'recordID', type: 'int', mapping: 'recordID'},
{name: 'ClientID', type: 'int', mapping: 'clientID'},
{name: 'CompanyName', type: 'string', mapping: 'companyName'}
])
});

There are several problems with your configuration. First of all the id-property of the read should be the idProperty-property. The the id-property of the store should be the storeId-property (id is deprecated). And then your variable is called frmClientStore while you're referencing clientStore in your code (might be a typo).
var frmClientStore = new Ext.data.Store({
storeId: 'frmClientStore',
proxy: new Ext.data.HttpProxy({
url: 'url here',
method: 'POST'
}),
reader: new Ext.data.JsonReader({
root: 'rows',
idProperty: 'recordID'
},[
{name: 'recordID', type: 'int', mapping: 'recordID'},
{name: 'ClientID', type: 'int', mapping: 'clientID'},
{name: 'CompanyName', type: 'string', mapping: 'companyName'}
])
});
And finally: are you sure, your store has been loaded when you try to retrieve records from it?
Try
frmClientStore.load({
callback: function(rs) {
console.log(rs);
console.log(this.find('ClientID', '37'));
}
});

The way that you've listed should be correct. However, I should point out that the field name is case sensitive. It is also possible that it is searching for a string (as you've listed) instead of a number (which may be what you want).
Supposing that 'ClientID' is the correct field name, you should try the following:
var index = clientStore.find('ClientID', 37);
EDIT
Also, I've just noticed that something looks off about your JsonReader. Shouldn't it be more like this:
//...
reader: new Ext.data.JsonReader({
root: 'rows',
id: 'recordID'
fields: [ //list fields here as part of the JsonReader
{name: 'recordID', type: 'int', mapping: 'recordID'},
{name: 'ClientID', type: 'int', mapping: 'clientID'},
{name: 'CompanyName', type: 'string', mapping: 'companyName'}
]
})

Related

Realm read data with relationship

I'm working on realm to make it work offline as local db in Electron. Now I want to make join(aggregation), so I defined a relationship between two schema's but then the data is not getting synced. It would be great to get help.
Here's my schema:
const articleMetaSchema = {
name: 'articlemeta',
properties: {
_id: 'objectId?',
catalog_id: 'objectId?',
content: 'objectId?',
createdAt: 'date?',
description: 'string?',
main_image_url: 'string?',
origin_type: 'string?',
pub_date: 'date?',
publication: 'objectId?',
sub_title: 'string?',
title: 'string?',
updatedAt: 'date?',
url: 'string?'
},
primaryKey: '_id'
}
const articleSchema = {
name: 'article',
properties: {
_id: 'objectId?',
active_search: 'bool?',
article_meta: 'articlemeta?',
catalog_id: 'objectId?',
content: 'objectId?',
createdAt: 'date?',
flagged: 'bool?',
owner_id: 'objectId?',
rating: 'int?',
read: 'bool?',
status: 'string?',
status_updated_at: 'date?',
updatedAt: 'date?'
},
primaryKey: '_id'
}
config = {
schema,
path: getDBPath(),
sync: {
user: app.currentUser,
partitionValue: new ObjectID(getCatalogId()),
error: (error) => {
console.log(error.name, error.message)
}
}
}
let realm = await Realm.open(config)
// query
I want to query and get the article result and in article schema we have defined a key 'article_meta' which is and objectId. Now I want article result with all the properties with article_meta as an object fetched on the basis of (article.article_meta = articlemeta._id)
Expected result:
[{ _id: '1', catalog_id: '', content: '', createdAt: '', main_image_url: '', origin_type: '', pub_date: '', publication: '', sub_title: '', title: '', updatedAt: '', url: '', article_meta: {} }, {..}, {..}]
Edit:
As pointed out in a comment, there is a bit of ambiguity in the question as the text doesn't match the code. The code shows the parent object article having a child object articlemeta which is generally correct and how relationships are built in Realm. Accessing child objects by querying their objectId is generally unnecessary if the relationship is built in a "Realmy" way as shown in this answer.
-- Original Answer below --
Realm objects can reference 'joined' realm objects via dot notation. from the docs
Filter on Related and Embedded Object Properties
To filter a query based on a property of an embedded object or a
related object, use dot-notation as if it were in a regular, nested
object.
So for example, a Person object has a Dog object as one of it's properties and you want to get that pesons' dogs name.
Let's get a specific person by their _id
const person = realm.objectForPrimaryKey("Person", 1234)
if we then want the persons dogs name
const dogName = person.dog.dog_name
In your case you can get a specific article, and then access all of the articlemeta properties using dot notation
const article = realm.objectForPrimaryKey("article", 1234)
and then access the rest of the properties through dot notiation
const id = article._id
const catalogId = article.catalog_id
const mainImageUrl = article.article_meta.main_image_url
As you can see, a query is not needed (for this example) as the Realm objects know their own child properties and can be accessed via dot notation.

Elasticsearch english language analyzer with nodejs

First time trying to implement elastic search using aws hosted service with nodejs. Referred to the official docs and came up with this:
//1. create index
client.indices.create({ index: 'products' });
//2. mapping
client.indices.putMapping({
index: 'products',
type: 'products',
body: {
properties: {
'product_name': {
'type': 'string',
"analyzer": "english"
},
'product_description': {
'type': 'string',
"analyzer": "english"
}
}
}
});
//3. import documents..
product_name: Testing
//4. search
client.search({
index: 'products',
type: 'products',
q: keywords,
analyzer: 'english',
size: 10
});
Now, if I search for 'Testing' or 'Token Testing', this returns 1 result. But if I test passing 'Test' or 'Tist' as a keyword, seems the analyzer isn't picking up and I get no results.
Updated: Added analyzer: 'english' according to #Val answer, but still no results for 'Test' or 'Tist'.
That's because when using the q parameter, a query_string query is made and the default analyzer of your input string is the standard analyzer.
You have two choices here:
A. Include the field name in your query string:
client.search({
index: 'products',
type: 'products',
q: 'product_name:' + keywords, <--- modify this
size: 10
});
B. Specify english as the query-time analyzer to produce the same tokens as has been previously indexed:
client.search({
index: 'products',
type: 'products',
q: keywords,
analyzer: 'english', <--- or add this
size: 10
});

Creating forms in Aposstrophe CMS

I am following this tutorial to create a form in my project, which is leveraging the Apostrophe CMS. When i follow the tutorial, I am able to create the form and submit, and understand how to view the form submission in the Admin Console.
However, when I begin to customize the form to fit my project-specific needs, I break the form, causing the form validation to fail. The error i get upon submitting the form is:
TypeError: Cannot read property 'length' of undefined
at Object.convertString [as convert] (user.js:727)
at user.js:145
at async.js:181
at iterate (async.js:262)
at Object.async.forEachOfSeries.async.eachOfSeries (async.js:281)
at Object.async.forEachSeries.async.eachSeries (async.js:214)
at Object.self.convert (user.js:127)
at convert (always.js:57)
at async.js:718
at iterate (async.js:262)
My changes, other then adjusting the field definition object of my contact-form:index.js file, are mostly in the contact-form-widgets:widget.html file.
In the tutorial, the contact-form-widgets:widget.html view imports apostrophe-schemas:macros.html, and uses html files from the apostrophe-schemas and apostrophe-ui modules to build the html of the form. My specific questions therefore have to do with the importance of those two modules. Are those modules simply used for the front end display of the form? Do the contents of the views of those modules have any bearing on the submission and post-submissions tasks of the form? If the answer is negative, this means I am not configuring the form correctly, so therefore, are there any resources to help solve that problem?
Here is my contact-form:index.js config file:
var async = require('async');
module.exports = {
extend: 'apostrophe-pieces',
name: 'contact-form',
label: 'Contact Form',
alias: 'contactForm',
addFields: [
{
name: 'name',
type: 'string',
label: 'First & Last Name',
required: true
},
{
name: 'company',
type: 'string',
label: 'Company Name',
required: true
},
{
name: 'email',
type: 'string',
label: 'Email Address',
required: true
},
{
name: 'phone',
type: 'string',
label: 'Phone Number & Extension',
required: true
},
{
name: 'subject',
type: 'string',
label: 'Subject',
required: true
},
{
name: 'message',
type: 'string',
label: 'Message',
textarea: true,
placeholder: "Don't be stupid"
}
],
permissionsFields: false,
afterConstruct: function(self) {
self.setSubmitSchema();
},
construct: function(self, options) {
self.setSubmitSchema = function() {
self.submitSchema = self.apos.schemas.subset(self.schema,
[ 'name', 'company', 'email', 'phone', 'subject', 'message' ]
);
};
self.submit = function(req, callback) {
var piece = {};
return async.series([
convert,
insert
], callback);
function convert(callback) {
return self.apos.schemas.convert(req, self.schema, 'form', req.body, piece, callback);
}
function insert(callback) {
return self.insert(req, piece, { permissions: false }, callback);
}
};
}
};
I'm the lead developer of Apostrophe at P'unk Avenue. We had some conversation in another forum but just for the record, there turned out to be two issues:
The form was submitting on any button click because that is what button elements do when they are of type "submit," and "submit" is the default value for type (at least in some browsers). It's not an Apostrophe issue and can be resolved by setting the type attribute as desired.
The form markup was custom and did not have wrapper elements such as data-name="title", etc. (corresponding to the schema) around the actual form field elements. You may use custom markup but all of the "moving parts" found in our official schemaMacros.html need to be there, i.e. the data attributes need to exist.
We do plan to make it easier to use custom markup without those wrappers, at least in cases where we can figure out which fields are which without them.
FYI, an element of type="file" will not work out of the box, but check out the attachment field type in apostrophe's schemas, which is pretty amazing for that role.

Retuning complex tree like structures in NEO4J without duplication

I have a method getPhotosInBucket which is to return all photos where a [:IN] relationship exists in a given bucket where each photo has its own set of relationships to Meta nodes that each contain properties corresponding to a different version of the image eg. small, medium, thumbnail etc. To make things even more complicated, each photo also has a creator and each creator has a thumbnail which like a photo has multiple Meta nodes related to it.
Below is a cut down version of what would be returned. In this example there is only one user who created the bucket and created each photo but in the real world user James could have a bucket containing 100 different images each with their own creator, thumbnail and creator thumbnail.
The query used to return this data is a little verbose and was just to demonstrate my structure a little bit and generate a visual graph:
MATCH (album:Asset:Album:Bucket {name: 'Bucketjamesprivate'})
MATCH (album)<-[:CREATED]-(creator)
OPTIONAL MATCH (album)<-[:THUMBNAIL]-(albumThumb)<-[:META]-(albumThumbMeta)
OPTIONAL MATCH (creator)<-[:THUMBNAIL]-(creatorThumb)
OPTIONAL MATCH (creatorThumb)<-[:META]-(creatorThumbMeta)
OPTIONAL MATCH (album)<-[:IN]-(photos)<-[:META]-(meta)
OPTIONAL MATCH (photos)<-[:CREATED]-(photoOwner)<-[:THUMBNAIL]-(photoThumbnail)<-[:META]-(photoThumbnailMeta)
RETURN DISTINCT album, albumThumb, albumThumbMeta, creator, creatorThumb, photos, meta, photoOwner, photoThumbnailMeta
This ends up returning the following:
As you can see, James created 1 bucket, 1 bucket thumbnail with 3 meta nodes, 2 photos IN the bucket each with 3 meta nodes and finally he has a thumbnail with 3 meta nodes.
The actual number of rows returned is 54 which can only grow exponentially when I have even just a handful of photos in a bucket to return so perhaps there is a more performant way of doing this.
I have tried using the collect method but it introduces some strange duplication which I'm sure is expected but I don't understand it well enough to know why.
The object I would like my method to return in the end would be something like this:
{
album: {
name: 'etc',
foo: 'bar',
bar: 'foo'
},
albumThumb: [
{
type: 'small',
src: 'www.foo.com/small'
},
{
type: 'medium',
src: 'www.foo.com/medium'
}
],
creator: {
name: 'James',
foo: 'bar'
},
creatorThumb: [
{
type: 'small',
src: 'www.foo.com/small'
},
{
type: 'medium',
src: 'www.foo.com/medium'
}
],
photos: [
{
photo: {
name: 'Photo 1',
date: '112432543636'
},
meta: [
{
type: 'small',
src: 'www.foo.com/small'
},
{
type: 'medium',
src: 'www.foo.com/medium'
}
],
creator: {
name: 'James',
foo: 'bar'
},
creatorThumb: [
{
type: 'small',
src: 'www.foo.com/small'
},
{
type: 'medium',
src: 'www.foo.com/medium'
}
]
},
{
photo: {
name: 'Photo 2',
date: '112432543636'
},
meta: [
{
type: 'small',
src: 'www.foo.com/small'
},
{
type: 'medium',
src: 'www.foo.com/medium'
}
],
creator: {
name: 'James',
foo: 'bar'
},
creatorThumb: [
{
type: 'small',
src: 'www.foo.com/small'
},
{
type: 'medium',
src: 'www.foo.com/medium'
}
]
}
]
}
Be it a photo in a bucket or a photo that is a thumbnail of some other node, there will only be a handful of meta nodes for each photo.
I'd also like to allow the client on the front end to paginate the photos, is there a way I can LIMIT and SKIP the photos IN the bucket?
Should I approach this differently and make 2 separate transactions? One to get the album, albumThumb, creator, creatorThumb and another to get the photos and associated thumbs?
I have a bit more time now, let me give it a shot ;)
MATCH (album:Asset:Album:Bucket {name: 'Bucketjamesprivate'})
MATCH (album)<-[:CREATED]-(creator)
OPTIONAL MATCH (album)<-[:THUMBNAIL]-(albumThumb)<-[:META]-(albumThumbMeta)
WITH
album,
collect({src: albumThumb.src, type: albumThumbMeta.type}) AS albumThumbs,
creator
OPTIONAL MATCH (creator)<-[:THUMBNAIL]-(creatorThumb)<-[:META]-(creatorThumbMeta)
WITH
album,
albumThumbs,
creator,
collect({src: creatorThumb.src, type: creatorThumbMeta.type}) AS creatorThumbs
OPTIONAL MATCH (album)<-[:IN]-(photo)<-[:META]-(photoMeta)
OPTIONAL MATCH
(photo)<-[:CREATED]-(photoOwner)<-[:THUMBNAIL]-(ownerThumb)
<-[:META]-(ownerThumbMeta)
WITH
album,
albumThumbs,
creator,
creatorThumbs,
photo,
collect({src: photo.src, type: photoMeta.type}) AS photoMeta,
photoOwner,
collect({src: ownerThumb.src, type: ownerThumbMeta.type}) AS ownerThumbs
RETURN
album,
albumThumbs,
creator,
creatorThumbs,
collect({
photo: photo,
meta: photoMeta,
owner: photoOwner,
ownerThumbs: ownerThumbs}) AS photos
Hopefully that will do it for you, or at least get you close enough!
This is my CREATE statement, BTW, in case anybody want to give it a shot:
CREATE
(bucket:Bucket {name: 'Bucketjamesprivate'})<-[:CREATED]-(james:Person {name: 'James'}),
(p1:Photo)-[:IN]->(bucket),
(p1)<-[:CREATED]-(james),
(p1)<-[:META]-(:Meta {type: 'small'}),
(p1)<-[:META]-(:Meta {type: 'medium'}),
(p1)<-[:META]-(:Meta {type: 'small_sq'}),
(p2:Photo)-[:IN]->(bucket),
(p2)<-[:CREATED]-(james),
(p2)<-[:META]-(:Meta {type: 'small'}),
(p2)<-[:META]-(:Meta {type: 'medium'}),
(p2)<-[:META]-(:Meta {type: 'small_sq'}),
(bucket_thumb:Thumbnail)-[:THUMBNAIL]->(bucket),
(bucket_thumb)<-[:CREATED]-(james),
(bucket_thumb)<-[:META]-(:Meta {type: 'small'}),
(bucket_thumb)<-[:META]-(:Meta {type: 'medium'}),
(bucket_thumb)<-[:META]-(:Meta {type: 'small_sq'}),
(james_thumb:Thumbnail)-[:THUMBNAIL]->(james),
(james_thumb)<-[:CREATED]-(james),
(james_thumb)<-[:META]-(:Meta {type: 'small'}),
(james_thumb)<-[:META]-(:Meta {type: 'medium'}),
(james_thumb)<-[:META]-(:Meta {type: 'small_sq'})

Grid store config throws "Uncaught TypeError: Cannot read property 'buffered' of undefined"

I have form and grid. the user must enter data in form fields then display related records in the grid.
I want to implement a search form, e.g: user will type the name and gender of the student,
then will get a grid of all students have the same name and gender.
So, I use Ajax to send form fields value to PHP and then create a json_encode which will be used in grid store.
I am really not sure if my idea is good. But I haven't found another way to do that.
The problem is there is a mistake in my store but I couldn't figure out what it is. I get this error:
Uncaught TypeError: Cannot read property 'buffered' of undefined
My View:
{
xtype: 'panel',
layout: "fit",
id: 'searchResult',
flex: 7,
title: '<div style="text-align:center;"/>SearchResultGrid</div>',
items: [{
xtype: 'gridpanel',
store: 'advSearchStore',
id: 'AdvSearch-grid',
columns: [{
xtype: 'gridcolumn',
dataIndex: 'name',
align: 'right',
text: 'name'
}, {
xtype: 'gridcolumn',
dataIndex: 'gender',
align: 'right',
text: 'gender'
}
],
viewConfig: {
id: 'Arr',
emptyText: 'noResult'
},
requires: ['MyApp.PrintSave_toolbar'],
dockedItems: [{
xtype: 'PrintSave_tb',
dock: 'bottom',
}]
}]
}
My Controller:
.
.
.
xmlhttp.open("GET","AdvSearch.php?search_name="+search_name,true);
xmlhttp.send(null);
My PHP script:
if (!$con) {
throw new Exception("Error in connection to DB");
}
$query ="SELECT name, gender FROM students WHERE name ILIKE '%$search_name%' ";
$result = pg_query($query);
while ($row = pg_fetch_array($result)) {
$Arr[] = array('name' => $row[0], 'gender' => $row[1]);
}
$searchResult_list = array();
$searchResult_list['success'] = true;
$searchResult_list['Arr'] = $Arr;
$searchResult_list['totalCount'] = count( $searchResult_list['Arr'] );
echo json_encode($searchResult_list);
if (!$result)
die("Error in query: " . pg_last_error());
pg_close($con);
My Store, Model:
Ext.define('AdvSearchPost', {
extend: 'Ext.data.Model',
proxy: {
type: 'ajax',
url: 'AdvSearch.php',
reader: {
type: 'json',
root: 'Arr',
totalProperty: 'totalCount'
}
},
fields: [{
name: 'name'
}, {
name: 'type_and_cargo'
}
]
});
advSearchStore = Ext.create('Ext.data.Store', {
pageSize: 10,
model: 'AdvSearchPost'
});
Well it is just a typo of your storename.
The error Uncaught TypeError: Cannot read property 'buffered' of undefinedonly indicates that the store could not be bound. It may be a bit misleading.
Try the grid with either
store: advSearchPost
or
store: Ext.StoreMgr.lookup('AdvSearchPost') // if in any form a controller takes care about your store
and it will work.
Edit
I guess you haven't any controller so I recommend you to create your store like this
Ext.create('Ext.data.Store', {
pageSize: 10,
model: 'AdvSearchPost',
storeId: 'AdvSearchPost'
});
That will enable you to receive the store by the StoreManager from everywhere (after it is created). That will also enable the last statement to work without any controller.
Even if you call like this..
store: Ext.StoreMgr.lookup('bla bla bla') won't throw any error in the console.
Replace store parameter with storeId and then assign your actual store to it which will connect to your actual store. storeId:advSearchPost

Resources