Sanity.io GROQ - Retrive document by highest reference count in other documents - javascript

I have a tag document that looks like
{
name: 'tag',
title: 'Tag',
type: 'document',
fields: [
{
name: 'label',
title: 'Label',
type: 'string',
}
]
}
And page document that looks like
{
name: "page",
title: "Page",
type: "document",
fields: [
{
name: "title",
title: "Title",
type: "string",
},
{
name: "tags",
title: "Tags",
type: "array",
of: [{ type: "reference", to: [{ type: "tag" }] }],
}
]
}
And another article document that looks like
{
name: "article",
title: "Article",
type: "document",
fields: [
{
name: "title",
title: "Title",
type: "string",
},
{
name: "description",
title: "Description",
type: "text",
},
{
name: "tags",
title: "Tags",
type: "array",
of: [{ type: "reference", to: [{ type: "tag" }] }],
}
]
}
I am unable to figure out how to get the tags with the highest reference count used across pages and articles
An extension of this question would be to get the top 10 highest tags used across the site.
I've been struggling for a while now. Any help would be appreciated.
Thank you team.

You can likely accomplish this by constructing a query that first gets all tags, then uses the count function to further filter them. Something like the following:
*[_type == 'tag'] {
...,
'totalReferences': count(*[_type in ['page', 'article'] && references(^._id))
} | order(totalReferences desc) [0...10]
This may not be very performant in very large datasets, though.

Related

Conditionally Filter Options for References in Sanity IO

I have 3 schema,
Menu
Section
Sub-Section
i want to conditionally filter the list of options provided based on the current object. Lets say i want to create a new sub-section which is under Pizza Menu so i will input Menu: Pizza (I created it before) and so section input should only accept and display all the available sections under pizza menu only.
Code:
subSection.js
export default {
name: 'sub-section',
title: 'Sub-Section',
type: 'document',
fields: [
{ name: 'title', type: 'string' },
{ name: 'description', type: 'string' },
{
name: 'menu',
type: 'reference',
to: [{ type: 'menu' }],
},
{
name: 'section',
type: 'reference',
to: [{ type: 'section' }],
options: {
filter: 'menu == references($menu)', // this does not work
filterParams: { menu: 'Neopolitan' }, // ^ ^ This is static, cannot reference current object
},
},
],
};
section.js
export default {
name: 'section',
title: 'Section',
type: 'document',
fields: [
{ name: 'title', type: 'string' },
{ name: 'description', type: 'string' },
{
name: 'menu',
type: 'reference',
to: [{ type: 'menu' }],
},
],
};
menu.js
export default {
title: 'Menu',
name: 'menu',
type: 'document',
fields: [
{
title: 'Title',
name: 'title',
type: 'string',
},
],
};

How to filter references based on change in another reference?

I have created an object with 3 reference fields - categories, subcategories, and types. I want the subcategories to show subcategories related to the selected category.
{
title: "Product Category",
name: "category",
type: "object",
fields: [
{
name: "categories",
type: "reference",
to: [
{
type: "categories",
},
],
},
{
name: "subcategories",
type: "reference",
to: [
{
type: "subcategories",
},
],
},
{
name: "types",
type: "reference",
to: [
{
type: "types",
},
],
},
],
},
I tried the filter option as mentioned in docs but can't seem to get it working so I removed it.
This is how I defined the categories and subcategories.
// categories.js
export default {
name: "categories",
type: "document",
title: "Categories",
fields: [
{
name: "category",
type: "string",
title: "Category name",
},
{
name: "slug",
title: "Slug",
type: "slug",
description: "URL friendly name",
options: {
source: "category",
maxLength: 96,
},
},
{
title: "Description",
name: "description",
type: "text",
},
],
};
// subcategories.js
export default {
name: "subcategories",
type: "document",
title: "Subcategories",
fields: [
{
name: "subcategory",
type: "string",
title: "Subcategory name",
},
{
name: "slug",
title: "Slug",
type: "slug",
description: "URL friendly name",
options: {
source: "subcategory",
maxLength: 96,
},
},
{
name: "categories",
type: "reference",
to: [
{
type: "categories",
},
],
},
],
};
Any help is appreciated.
Based on your schema, I think this should work:
export default {
title: "Product Category",
name: "category",
type: "object",
fields: [
{
name: "categories",
type: "reference",
to: [
{
type: "categories",
},
],
},
{
name: "subcategories",
type: "reference",
to: [
{
type: "subcategories",
},
],
options: {
filter: 'references($category._id)',
filterParams: {category: 'categories'}
}
},
{
name: "types",
type: "reference",
to: [
{
type: "types",
},
],
},
],
}
This adds the filter and filterParams to the options object on the subcategories field. This should narrow down the items that is selectable in the reference picker.
EDIT:
This should get the job done for you. It will also not yield any results if categories isn't set already:
export default {
title: 'Product Category',
name: 'category',
type: 'object',
fields: [
{
name: 'categories',
type: 'reference',
to: {type: 'categories'}
},
{
name: 'subcategories',
type: 'reference',
to: {type: 'subcategories'},
options: {
filter: ({ document }) => {
console.log(document)
if (!document.category || !document.category.categories) {
return;
}
return {
filter: "categories._ref == $category",
params: {
category: document.category.categories._ref,
}
}
}
}
}
]
}

Ext JS SortType treecolumn

Using ExtJS 4.2.3. Have form with treecolumn xtype field which contains string value with number in begin. Column has 3 lvls of structure. On first lvl sort needs to be in order like (2, 3, 5, 40, 100 and etc).
After picking third lvl value in selection form, value in box will look like:
3.ABC.<BR>3.23.ABCCDD.<BR>3.23.5. ABCC
Sample of code:
enter Picker = new Project.Picker({
title: "Title1",
proxyCfg: {
url: Ext.state.Manager.get("url") + "TreeList",
type: "ajax"},
idProperty: "id",
defaultRootId: "NULL",
nodeParam: "parent_Code",
PickerCfg: [
{ name: "id", type: "string", isSC: false },
{ xtype: "treecolumn", name: "Fieldname", header: "Header1", type: "string", isSC: true, isHC: true },
{ name: "name2", type: "string" },
{ name: "code", header: "Header3", type: "string", isSC: true}],
viewConfig: {
listeners: {
itemdblclick: function (view, record) {
Order_Form.getComponent("Grid").selModel.getSelection()[0].set("id", record.get("id"));
Order_Form.getComponent("Grid").selModel.getSelection()[0].set("Fieldname", record.get("Fieldname"));
Order_Form.getComponent("Grid").selModel.getSelection()[0].set("code", record.get("code"));
trigger.setValue(record.get("name2"));
this.up().up().destroy();
}
}
},
sorters: [{
property: "code",
direction: "ASC"
}]
}).show(this, function () { this.getComponent(0).DMS_search(); Picker.getComponent(0).getView().refresh(); });
}
},
tpl: "<table class='Gridd' style='border-collapse: collapse; border: medium none;'><tr><td><b>[Header1]: </b></td><td style='width:100%;'>{Name2}</td></tr><tr><td><b>[Header3]: </b></td><td>{code}</td></tr></table>"
Asking for help with sorting in selection form.

Extjs 5, data model association & load nested data

trying to make this work....
I want to load nested data on two object model
Ext.application({
name : 'MyApp',
launch : function() {
Ext.define('MyApp.model.Address', {
extend: 'Ext.data.Model',
entityName: 'Address',
fields: [
{
name: 'id',
type: 'int'
},
{
name: 'addressLine',
type: 'string'
},
{
name: 'city',
type: 'string'
},
{
name: 'created',
type: 'date',
dateFormat: 'time',
persist: false
}
]
});
Ext.define('MyApp.model.User', {
extend: 'Ext.data.Model',
entityName: 'User',
fields: [
{
name: 'id',
type: 'int'
},
{
name: 'address',
reference: 'Address'
},
{
name: 'name',
type: 'string'
},
{
name: 'lastname',
type: 'string'
},
{
name: 'created',
type: 'date',
dateFormat: 'time',
persist: false
}
]
});
var user = new MyApp.model.User({
"id": 1,
"name": "Pedro",
"lastname": "Carbonell",
"address": {
"id": 1,
"addressLine": "Bailen 22",
"city": "Barcelona",
"created": 1420668866000
},
"created": 1420668866000
});
console.info(user);
console.info(user.getAddress());
}});
It's result on no error when created the user, but when I access to associated data via user.getAddress() it returned an exception:
Uncaught Error: The model ID configured in data ("[object Object]") has been rejected by the int field converter for the id fieldext-all-debug.js
Try to define proxy like memory or localstorage on model definitions, but the result it is the same.
Ext fiddle: https://fiddle.sencha.com/#fiddle/h2d
Any help will be appreciated!
Solved, but only find this solution: when use loadRawData...
var store = new Ext.data.Store({
model: MyApp.model.User
});
store.loadRawData({
"id": 1,
"name": "Pedro",
"lastname": "Carbonell",
"address": {
"id": 1,
"addressLine": "Bailen 22",
"city": "Barcelona",
"created": 1420668866000
},
"created": 1420668866000
});
console.info(store.first());
console.info(store.first().getAddress());
sample at this new fiddle: https://fiddle.sencha.com/#fiddle/h4e
you'r right, ext is a bit flaky, very....
I've been playing around with the code in your fiddle and not been able to get the association working the official way as of yet.
I simulated the functionality using this code:
Ext.define('MyApp.model.User', {
extend: 'Ext.data.Model',
fields: [{
name: 'id',
type: 'int'
}, {
name: 'name',
type: 'string'
}, {
name: 'lastname',
type: 'string'
}, {
name: 'created',
type: 'date',
dateFormat: 'time',
persist: false
}],
getAddress: function() {
if ('undefined' === this.data.address) {
return null;
}
return Ext.create('Address', this.data.address);
}
});
Basically I've removed the association and created a custom function to create a model record based off of the raw data passed in, You could also return a new, empty model if the address data does not exist instead of null, I used null as it's easier to determine whether you have a valid address record or not.
As already mentioned - this is not the official way to do this, I will have another play around with the fiddle and post a better solution once I find it, this may help in the meantime.
Using the original code, I made a few modifications and now it appears to be working.
Ext.application({
name : 'MyApp',
launch : function() {
Ext.define('MyApp.model.Address', {
extend: 'Ext.data.Model',
//entityName: 'Address',
fields: [
{
name: 'id',
type: 'int'
},
{
name: 'addressLine',
type: 'string'
},
{
name: 'city',
type: 'string'
},
{
name: 'created',
type: 'date',
dateFormat: 'time',
persist: false
}
],
hasMany: 'User'
});
Ext.define('MyApp.model.User', {
extend: 'Ext.data.Model',
//entityName: 'User',
fields: [
{
name: 'id',
type: 'int'
},
{
name: 'name',
type: 'string'
},
{
name: 'lastname',
type: 'string'
},
{
name: 'created',
type: 'date',
dateFormat: 'time',
persist: false
}
],
hasMany: { model: 'Address', name: 'Address' }
});
var user = new MyApp.model.User({
"id": 1,
"name": "Pedro",
"lastname": "Carbonell",
"address": {
"id": 1,
"addressLine": "Bailen 22",
"city": "Barcelona",
"created": 1420668866000
},
"created": 1420668866000
});
console.info(user);
console.info(user.data.address);
}
});
Is this the sort of thing you're after? I set Address manually on the User model. Not ideal but it's interpreted correctly as a record then.
Ext.define('MyApp.model.Address', {
extend: 'Ext.data.Model',
entityName: 'Address',
fields: [
{
name: 'id',
type: 'int'
},
{
name: 'addressLine',
type: 'string'
},
{
name: 'city',
type: 'string'
},
{
name: 'created',
type: 'date',
dateFormat: 'time',
persist: false
}
]
});
Ext.define('MyApp.model.User', {
extend: 'Ext.data.Model',
entityName: 'User',
fields: [
{
name: 'id',
type: 'int'
},
{
name: 'addressId',
reference: 'Address'
},
{
name: 'name',
type: 'string'
},
{
name: 'lastname',
type: 'string'
},
{
name: 'created',
type: 'date',
dateFormat: 'time',
persist: false
}
]
});
var user = new MyApp.model.User({
"id": 1,
"name": "Pedro",
"lastname": "Carbonell",
"created": 1420668866000
});
var addr = new MyApp.model.Address({
"id": 1,
"addressLine": "Bailen 22",
"city": "Barcelona",
"created": 1420668866000
});
user.setAddress(addr);
console.info(user);
console.info(user.getAddress());

ExtJS 3.3 Format.Util.Ext.util.Format.dateRenderer returning NaN

The Store
var timesheet = new Ext.data.JsonStore(
{
root: 'timesheetEntries',
url: 'php/scripts/timecardEntry.script.php',
storeId: 'timesheet',
autoLoad: true,
fields: [
{ name: 'id', type: 'integer' },
{ name: 'user_id', type: 'integer' },
{ name: 'ticket_number', type: 'integer' },
{ name: 'description', type: 'string' },
{ name: 'start_time', type: 'string' },
{ name: 'stop_time', type: 'string' },
{ name: 'client_id', type: 'integer' },
{ name: 'is_billable', type: 'integer' }
]
}
);
A section of my GridPanel code:
columns: [
{
id: 'ticket_number',
header: 'Ticket #',
dataIndex: 'ticket_number'
},
{
id: 'description',
header: 'Description',
dataIndex: 'description'
},
{
id: 'start_time',
header: 'Start',
dataIndex: 'start_time',
renderer: Ext.util.Format.dateRenderer('m/d/Y H:i:s')
}
...
From the server, I receive this JSON string:
{
timesheetEntries:[
{
"id":"1",
"user_id":"1",
"description":null,
"start_time":"2010-11-13 11:30:00",
"stop_time":"2010-11-13 15:50:10",
"client_id":null,
"is_billable":"0"
}
My grid panel renders fine. However, my start and stop time columns read 'NaN/NaN/NaN NaN:NaN:NaN' and I don't know why.
If your data has "2010-11-13 11:30:00" shouldn't your format be 'Y-m-d H:i:s'?
EDIT: Sorry, the grid config should be OK -- I was referring to the dateFormat value in your store's field definition, which should be 'Y-m-d H:i:s' so that your incoming data can be properly mapped to your column model. You should also include type: 'date'. You're not showing your store config, but the problem is likely one of those things being wrong.
Try this
function renderDate(v,params,record)
{
var dt = new Date(v);
if (!isNaN(dt.getDay())) {
return dt.format('d/m/Y');
}
return '-';
}
A very simple way to do it:
return Ext.util.Format.date(val,'m/d/Y');

Categories

Resources