I have read many questions/answers and tutorials and I still fail to implement hierarchical model in Sencha Touch. The root model is Tag. Each Tag has many Items. Here is my model:
The root tag:
app.models.Tag = Ext.regModel("Tag", {
fields : [ {
name : "id",
type : "int"
}, {
name : "name",
type : "string"
}],
associations : {
type : "hasMany",
model : "TagItem",
name : "items"
}
});
Adjected TagItem
app.models.TagItem = Ext.regModel("TagItem", {
fields : [ {
name : "id",
type : "int"
}, {
name : "title",
type : "string"
}, {
name : "type",
type : "string"
}, {
name : "tag_id",
type : "int"
}],
associations : {
belongsTo : {
model : "Tag",
name : "items"
}
}
});
TagStore:
app.stores.tagItems = new Ext.data.Store({
model : "app.models.TagItem",
proxy : {
type : 'scripttag',
root : 'items',
url : 'http://www.s-lab.cz/ios/api/tags.php'
}
});
Tags:
app.stores.tags = new Ext.data.Store({
model : "app.models.TagItems",
proxy : {
type : 'scripttag',
url : 'http://www.s-lab.cz/ios/api/tags.php'
}
});
When I try to load items from the store I get:
Uncaught TypeError: Cannot call method 'read' of undefined
My JSON looks like this:
stcCallback1005([
{
"id":1,
"name":"Doktor",
"url":"doktor",
"items":[
{
"type":"video",
"id":1,
"title":"First tag item",
"tag_id":1
},
{
"type":"article",
"id":1,
"title":"Second tag item - article",
"tag_id":1
},
{
"type":"article",
"id":2,
"title":"Third tag item - article",
"tag_id":1
},
{
"type":"video",
"id":2,
"title":"Fourth tag item",
"tag_id":1
}
]
},
{
"id":2,
"name":"Nemocnice",
"url":"nemocnice"
},
{
"id":3,
"name":"Sestra",
"url":"sestra"
}
]);
Update:
I changed the code with suggestions and the resulting JSON is like this:
stcCallback1005({
"results": [{
"id": 1,
"name": "Doktor",
"url": "doktor",
"items": [{
"type": "video",
"id": 1,
"title": "First tag item",
"tag_id": 1
}, {
"type": "article",
"id": 1,
"title": "Second tag item - article",
"tag_id": 1
}, {
"type": "article",
"id": 2,
"title": "Third tag item - article",
"tag_id": 1
}, {
"type": "video",
"id": 2,
"title": "Fourth tag item",
"tag_id": 1
}]
}, {
"id": 2,
"name": "Nemocnice",
"url": "nemocnice"
}, {
"id": 3,
"name": "Sestra",
"url": "sestra"
}]
});
But still I'm not able to access the subsequent items: app.stores.tags.getAt(0) works, but app.stores.tags.getAt(0).TagItems() does not (neither app.stores.tags.getAt(0).items or app.stores.tags.getAt(0).items() does). And also my template doesn't render correctly: <tpl for=".">{name}<ul><tpl for="items"><li>{title} ({type})</li></tpl></ul></tpl>
Any idea?
I think you don't need to assign a variable for model registration.
Ext.regModel("Tag", {
fields : [ {
name : "id",
type : "int"
}, {
name : "name",
type : "string"
}],
associations : {
type : "hasMany",
model : "TagItem",
name : "items"
}
});
So;
Ext.regModel("TagItem", {
fields : [ {
name : "id",
type : "int"
}, {
name : "title",
type : "string"
}, {
name : "type",
type : "string"
}, {
name : "tag_id",
type : "int"
}],
associations : {
belongsTo : {
model : "Tag",
name : "items"
}
}
});
Add reader to json and correct registered model names.
TagStore:
app.stores.tagItems = new Ext.data.Store({
model : "TagItem", //Use registered name
proxy : {
type : 'scripttag',
url : 'http://www.s-lab.cz/ios/api/tags.php'
reader: { //add reader to read from json
type: 'json',
root: 'results'
}
}
});
Tags:
app.stores.tags = new Ext.data.Store({
model : "Tag", //Use registered name
proxy : {
type : 'scripttag',
url : 'http://www.s-lab.cz/ios/api/tags.php'
reader: { //add reader to read from json
type: 'json',
root: 'results'
}
}
});
And finally maybe you need to change your json format in tags.php as;
{"results":[
{
"id":1,
"name":"Doktor",
"url":"doktor",
"items":[
{
"type":"video",
"id":1,
"title":"First tag item",
"tag_id":1
},
{
"type":"article",
"id":1,
"title":"Second tag item - article",
"tag_id":1
},
{
"type":"article",
"id":2,
"title":"Third tag item - article",
"tag_id":1
},
{
"type":"video",
"id":2,
"title":"Fourth tag item",
"tag_id":1
}
]
},
{
"id":2,
"name":"Nemocnice",
"url":"nemocnice"
},
{
"id":3,
"name":"Sestra",
"url":"sestra"
}
]
}
I hope it works or helps to correct your code.
Related
Suppose that I have a collection with documents like below
{
"location" : "Tokyo",
"region" : "Asia",
"attraction": {
"transportation" : "Subway",
"food" : {
"food_0" : {
"name" : "Sushi",
"price" : 100,
"restaurant" : "Ookinza"
},
"food_1" : {
"name" : "Sashimi",
"price" : 200,
"restaurant" : "Hibiki"
},
"food_2" : {
"name" : "N/A",
"price" : "N/A",
"restaurant" : "N/A"
}
}
}
},
{
"location" : "Taipei",
"region" : "Asia",
"attraction": {
"transportation" : "Subway",
"food" : {
"food_0" : {
"name" : "Bubble tea",
"price" : 50,
"restaurant" : "The Alley"
},
"food_1" : {
"name" : "Oyster cake",
"price" : 100,
"restaurant" : "Night market"
},
"food_2" : {
"name" : "N/A",
"price" : "N/A",
"restaurant" : "N/A"
}
}
}
},
{
"location" : "Toronto",
"region" : "North America",
"attraction": {
"transportation" : "Uber",
"food" : {
"food_0" : {
"name" : "Raman",
"price" : 300,
"restaurant" : "Kinto"
},
"food_1" : {
"name" : "Bubble tea",
"price" : 200,
"restaurant" : "Fresh Fruit"
},
"food_2" : {
"name" : "N/A",
"price" : "N/A",
"restaurant" : "N/A"
}
}
}
},
How do I find documents that have matching field in the child object of Food?
i.e. If I want to find document that has restaurant:"Fresh Tea"?
Currently what I have:
app.get(route, (req, res) => {
var detail = {};
if(req.query.location){
detail['location'] = req.query.location.toUpperCase();
}
if(req.query.region){
detail['region'] = req.query.region.toUpperCase();
}
if(req.query.transportation){
detail['attraction.transportation'] = new RegExp(req.query.transportation.split(","), "i"),
}
if(req.query.restaurant){
detail['attraction.food.food_0'] = req.query.restaurant;
}
db.collection(config.dbCollections.foodDB)
.aggregate([
$match: detail,
},
{
$lookup: {
... // code continues
Right now detail['attraction.food.food_0'] = req.query.restaurant is only able to find document that has matching food_0.restaurant, but I still can't find a way to make it check all child objects within "food".
Updated with more info:
User has the option to enter multiple search categories, and I want to combine all the search requests into "detail" and find all matching results. I.e. If user looks for transportation="Subway" and food="Bubble tea", then both Taipei and Toronto should come up as result.
Using dynamic value as field name is generally considered as anti-pattern and should be avoided. Nevertheless, you can convert the object attraction.food to an array of k-v tuple and perform the search with your criteria. For your case, $anyElementTrue with $map will help with processing the array.
db.collection.aggregate([
{
"$addFields": {
"test": {
"$anyElementTrue": {
"$map": {
"input": {
"$objectToArray": "$attraction.food"
},
"as": "t",
"in": {
$or: [
{
$eq: [
"$$t.v.transportation",
"Subway"
]
},
{
$eq: [
"$$t.v.name",
"Bubble tea"
]
}
]
}
}
}
}
}
},
{
$match: {
test: true
}
},
{
"$unset": "test"
}
])
Here is the Mongo Playground for your reference.
A possible aggregation pipeline
Add a temporary field using $addFields and $objectToArray which does something similar to javascript Object.entries()
Do the matching
Remove the added temporary field using $project 0
playground
db.collection.aggregate([
{
"$addFields": {
"foodArray": {
"$objectToArray": "$attraction.food"
},
},
},
{
"$match": {
"foodArray.v.restaurant": "Fresh Fruit"
}
},
{
"$project": {
"foodArray": 0
},
},
])
Here is my situation, i am importing from multiple data sources into my json backend.
The mapping file will look something like this sample below. So the question is how could i go about it to effectively look up the mapping on an import from this json file and use it when to import the data into my backend. So the concept is to pass 2 objects to my function, the mapping file and the json object which holds the data from the vendor. Then i have to use the mapping and loop thru data to create an object / doc and insert in my backend with correct mappings.
{
"vendor" : "ABCVendor",
"version" : "2.01",
"mappings" : [
{ "fieldName" : "fName",
"dbName" : "FirstName",
"required" : true,
"type" : "string"
},
{ "fieldName" : "mName",
"dbName" : "MiddleName",
"required" : false,
"type" : "string"
},
{ "fieldName" : "lName",
"dbName" : "LastName",
"required" : true,
"type" : "string"
}
]
}
Here is what the input would look like
{
"fname" : "Steve",
"mname" : "T",
"lname" : "Miller"
}
Ad here is what i would like to get out
{
"FirstName" : "Steve",
"MiddleName" : "T",
"LastName" : "Miller"
}
You could do something like this, if the insert is always the same.
this may not be the most performant way to do it though.
"use strict";
const fileConfig = {
"vendor": "ABCVendor",
"version": "2.01",
"mappings": [
{
"fieldName": "fName",
"dbName": "FirstName",
"required": true,
"type": "string"
},
{
"fieldName": "mName",
"dbName": "MiddleName",
"required": false,
"type": "string"
},
{
"fieldName": "lName",
"dbName": "LastName",
"required": true,
"type": "string"
}
]
};
const funcInput = {
"fName": "Steve",
"mName": "T",
"lName": "Miller"
};
function change(config, input) {
const result = {};
config.mappings.forEach((fe) => {
result[fe.dbName] = input[fe.fieldName];
});
return result;
}
console.log(change(fileConfig, funcInput))
You can do this all with reduce (although there does appear to be a casing difference in your mapping vs your object which ive used toLowerCase to get aeround - maybe uunncessary if that was just a typo on your part)
const config = {
"vendor" : "ABCVendor",
"version" : "2.01",
"mappings" : [
{ "fieldName" : "fName",
"dbName" : "FirstName",
"required" : true,
"type" : "string"
},
{ "fieldName" : "mName",
"dbName" : "MiddleName",
"required" : false,
"type" : "string"
},
{ "fieldName" : "lName",
"dbName" : "LastName",
"required" : true,
"type" : "string"
}
]
}
const input = {
"fname" : "Steve",
"mname" : "T",
"lname" : "Miller"
}
const result = config.mappings.reduce(
(acc, {fieldName, dbName}) => ({...acc, [dbName]: input[fieldName.toLowerCase()]})
,{})
console.log(result)
I'm new on mongodb, I have read documentation and I try to insert a document page with referenced id's of other documents but I have a validation fail.
That's my schema validation rules :
db.createCollection("page", {
capped: true,
size: 4500000000,
max: 6,
validator: {
$jsonSchema: {
bsonType: "object",
required: [ "title", "url", "elements" ],
additionalProperties: false,
properties: {
title: {
bsonType: "object",
required: [ "content_id" ],
properties: {
content_id: {
bsonType: "objectId"
}
}
},
url: {
bsonType: "string"
},
elements: {
bsonType: "array",
items: {
bsonType: "object",
required: [ "order" , "element_id" ],
properties: {
order: {
bsonType: "int"
},
element_id: {
bsonType: "objectId"
}
}
}
}
}
}
}
});
And this is what i try to insert (i add in variable the futur id Object and variable content and document already have the id's i need)
var page1 = ObjectId();
db.page.insertOne(
{
"_id": page1,
"title": {
"content_id": content5
},
"url": "/home",
"elements": [
{
"order": 1,
"element_id": element1
},
{
"order": 2,
"element_id": element2
},
{
"order": 3,
"element_id": element3
},
{
"order": 4,
"element_id": element4
}
]
}
);
Please why do I have this error? I don't understand what the problem is, is this schema good with what I'm trying to insert?
2020-04-07T18:55:35.513+0200 E QUERY [js] WriteError({
"index" : 0,
"code" : 121,
"errmsg" : "Document failed validation",
"op" : {
"_id" : ObjectId("5e8c72698d808f037e6adede"),
"title" : {
"content_id" : ObjectId("5e8c72128d808f037e6aded6")
},
"url" : "/home",
"elements" : [
{
"order" : 1,
"element_id" : ObjectId("5e8c724d8d808f037e6adeda")
},
{
"order" : 2,
"element_id" : ObjectId("5e8c724d8d808f037e6adedb")
},
{
"order" : 3,
"element_id" : ObjectId("5e8c724d8d808f037e6adedc")
},
{
"order" : 4,
"element_id" : ObjectId("5e8c724d8d808f037e6adedd")
}
]
}
}) :
WriteError({
"index" : 0,
"code" : 121,
"errmsg" : "Document failed validation",
"op" : {
"_id" : ObjectId("5e8c72698d808f037e6adede"),
"title" : {
"content_id" : ObjectId("5e8c72128d808f037e6aded6")
},
"url" : "/home",
"elements" : [
{
"order" : 1,
"element_id" : ObjectId("5e8c724d8d808f037e6adeda")
},
{
"order" : 2,
"element_id" : ObjectId("5e8c724d8d808f037e6adedb")
},
{
"order" : 3,
"element_id" : ObjectId("5e8c724d8d808f037e6adedc")
},
{
"order" : 4,
"element_id" : ObjectId("5e8c724d8d808f037e6adedd")
}
]
}
})
WriteError#src/mongo/shell/bulk_api.js:458:48
mergeBatchResults#src/mongo/shell/bulk_api.js:855:49
executeBatch#src/mongo/shell/bulk_api.js:919:13
Bulk/this.execute#src/mongo/shell/bulk_api.js:1163:21
DBCollection.prototype.insertOne#src/mongo/shell/crud_api.js:264:9
#(shell):1:1
Thank you for your answers
Okay, I got the solution, the problem was the additional rule Properties. So if it's on false, you have to add the _id property before inserting data because it considers _id as an additional property.
The bsonType: "int" can also make an error, so use number.
So with this validator rule i can insert my data ->
db.createCollection("page", {
capped: true,
size: 4500000000,
max: 6,
validator: {
$jsonSchema: {
bsonType: "object",
required: [ "_id", "title", "url", "elements" ],
additionalProperties: false,
properties: {
_id: {
bsonType: "objectId"
},
title: {
bsonType: "object",
required: [ "content_id" ],
properties: {
content_id: {
bsonType: "objectId"
}
}
},
url: {
bsonType: "string"
},
elements: {
bsonType: "array",
items: {
bsonType: "object",
required: [ "order" , "element_id" ],
properties: {
order: {
bsonType: "number"
},
element_id: {
bsonType: "objectId"
}
}
}
}
}
}
}
});
My document has a field that looks like this:
_source:
...
"produto_tags" : [
{
"id_produto_cor" : "1623153806",
"tags" : []
},
{
"id_produto_cor" : "875623985732",
"tags": []
},
{...}
...
I need to insert on this field another Object without rewrite the entire produto_tags
data to be inserted:
{
"id_produto_cor" : "312411",
"tags": []
},
and my final document will looks like this:
_source:
...
"produto_tags" : [
{
"id_produto_cor" : "1623153806",
"tags" : []
},
{
"id_produto_cor" : "875623985732",
"tags": []
},
{
"id_produto_cor" : "312411",
"tags": []
}
]
Im using NODE js, I`m using this but it rewrites what I put :
const query = {
doc: {
nome_relatorio: nome_relatorio,
produto_tags: produto_tags,
referencia_tags: referencia_tags,
}
};
return await esClient.update({
index: indexName,
body: query,
id: id,
method: 'post',
type: typeDoc,
})
1. You can use update_by_query api
POST <index_name>/_update_by_query
{
"script": {
"source": "ctx._source.produto_tags.add(params.product)",
"params": {
"product": {
"product_id": "1004600287",
"tags": []
}
}
},
"query": {
"match_all": {} --> select the document
}
}
2. Update api
POST <index_name>/_update/<doc_id>
{
"script": {
"source": "ctx._source.produto_tags.add(params.product)",
"lang": "painless",
"params": {
"product": {
"product_id": "11",
"tags": []
}
}
}
}
I have jstree setup to load all content via ajax and json. Is it possible for the script to execute my ajax/json url and keep sub-searching when possible, if it finds it open all sub nodes until its visible and select it (.jstree-clicked). And is such a feature built in, if not know any where I could start with this? I am not the most fluent at javascript.
Here is my setup:
$("#jstFormMirror").jstree({
"types" : {
"types" : {
"default" : {
"select_node" : function(e) {
this.toggle_node(e);
return true;
}
}
}
},
"ui" : {
"select_limit" : 1,
"selected_parent_close" : "select_parent"
},
"json_data" : {
"progressive_unload" : true,
"ajax" : {
"url" : "/back-end/json/categories.json",
"data" : function (n) {
return { id : n.attr ? n.attr("id") : 0 };
}
}
},
"plugins" : [ "themes", "json_data", "types", "ui" ],
"core": {
"animation": 100
}
}).bind("select_node.jstree", function(event, data) {
$("#category").val($(".jstree-clicked").parent().attr("rel"));
})
And he is a typical json response when the script loads a node:
[
{
"attr": {
"id": "87"
},
"data": {
"title": "Bevel Clusters-Over 350 Designs",
"attr": {
"href": "#",
"rel": "658"
}
},
"state": "closed"
},
{
"attr": {
"id": "394"
},
"data": {
"title": "Bevels, Straight Lines-Over 210 Shapes & Sizes",
"attr": {
"href": "#",
"rel": "321"
}
},
"state": "closed"
}
]
I want to execute:
$("#jstFormCategories").jstree("search", ID_HERE);
For this, DefiantJS is excellent (http://defiantjs.com).
This lib extends the global object JSON with the method "search" and enables you to search a JSON structure with XPath expressions.
To understand how easy XPath (which is a standardised query language) is, check out this tool;
http://www.defiantjs.com/#xpath_evaluator
Here is a working fiddle;
http://jsfiddle.net/hbi99/vV43F/
var data = [
{
"attr": {
"id": "87"
},
"data": {
"title": "Bevel Clusters-Over 350 Designs",
"attr": {
"href": "#",
"rel": "658"
}
},
"state": "closed"
},
{
"attr": {
"id": "394"
},
"data": {
"title": "Bevels, Straight Lines-Over 210 Shapes & Sizes",
"attr": {
"href": "#",
"rel": "321"
}
},
"state": "closed"
}
],
res = JSON.search( data, '//*[id=394]/../data' );
console.log( res[0].title );