I have a JSON looking like this:
{
"foo": {
"bar": {
"type": "someType",
"id": "ga241ghs"
},
"tags": [
{
"#tagId": "123",
"tagAttributes": {
"attr1": "AAA",
"attr2": "111"
}
},
{
"#tagId": "456",
"tagAttributes": {
"attr1": "BBB",
"attr2": "222"
}
}
]
},
"text": "My text"
}
Actually it's not split to multiple lines (just did it to give a better overview), so it's looking like this:
{"foo":{"bar":{"type":"someType","id":"ga241ghs"},"tags":[{"#tagId":"123","tagAttributes":{"attr1":404,"attr2":416}},{"#tagId":"456","tagAttributes":{"attr1":1096,"attr2":1103}}]},"text":"My text"}
I want to insert this JSON with Logstash to an Elasticsearch index. However, I want to insert a flattened JSON with the fields in the array combined like this:
"foo.bar.tags.tagId": ["123", "456"]
"foo.tags.tagAttributs.attr1": ["AAA", "BBB"]
"foo.tags.tagAttributs.attr2": ["111", "222"]
In total, the data inserted to Elasticsearch should look like this:
"foo.bar.type": "someType"
"foo.bar.id": "ga241ghs"
"foo.tags.tagId": ["123", "456"]
"foo.tags.tagAttributs.attr1": ["AAA", "BBB"]
"foo.tags.tagAttributs.attr2": ["111", "222"]
"foo.text": "My text"
This is my current Logstash .conf; I am able to split the "tags" array, but now I am getting 2 entries as a result.
How can I now join all tagIds to one field, attr1 values of the array to one field, and all attr2 values to another?
input {
file {
codec => json
path => ["/path/to/my/data/*.json"]
mode => "read"
file_completed_action => "log"
file_completed_log_path => ["/path/to/my/logfile"]
sincedb_path => "/dev/null"
}
}
filter {
split {
field => "[foo][tags]"
}
}
output {
stdout { codec => rubydebug }
}
Thanks a lot!
Nice example for my JSON iterator IIFE - no need for complex algos, just pick DepthFirst, sligthly modified path (new "raw" version) and that is it.
In case you like this JS answer, mind ticking accept flag under voting buttons.
In case you want different language, have also C# parser with similar iterators on same GitHub.
var src = {"foo":{"bar":{"type":"someType","id":"ga241ghs"},"tags":[{"#tagId":"123","tagAttributes":{"attr1":"AAA","attr2":"111"}},{"#tagId":"456","tagAttributes":{"attr1":"BBB","attr2":"222"}}],"text":"My text"}};
//console.log(JSON.stringify(src, null, 2));
function traverse(it) {
var dest = {};
var i=0;
do {
if (it.Current().HasStringValue()) {
var pathKey = it.Path(true).join('.');
var check = dest[pathKey];
if (check) {
if (!(check instanceof Array)) dest[pathKey] = [check];
dest[pathKey].push(it.Value());
} else {
dest[pathKey] = it.Value();
}
}
//console.log(it.Level + '\t' + it.Path(1).join('.') + '\t' + it.KeyDots(), (it.Value() instanceof Object) ? "-" : it.Value());
} while (it.DepthFirst());
console.log(JSON.stringify(dest, null, 2));
return dest;
}
/*
* https://github.com/eltomjan/ETEhomeTools/blob/master/HTM_HTA/JSON_Iterator_IIFE.js
* +new raw Path feature
*/
'use strict';
var JNode = (function (jsNode) {
function JNode(_parent, _pred, _key, _value) {
this.parent = _parent;
this.pred = _pred;
this.node = null;
this.next = null;
this.key = _key;
this.value = _value;
}
JNode.prototype.HasOwnKey = function () { return this.key && (typeof this.key != "number"); }
JNode.prototype.HasStringValue = function () { return !(this.value instanceof Object); }
return JNode;
})();
var JIterator = (function (json) {
var root, current, maxLevel = -1;
function JIterator(json, parent) {
if (parent === undefined) parent = null;
var pred = null, localCurrent;
for (var child in json) {
var obj = json[child] instanceof Object;
if (json instanceof Array) child = parseInt(child); // non-associative array
if (!root) root = localCurrent = new JNode(parent, null, child, json[child]);
else {
localCurrent = new JNode(parent, pred, child, obj ? ((json[child] instanceof Array) ? [] : {}) : json[child]);
}
if (pred) pred.next = localCurrent;
if (parent && parent.node == null) parent.node = localCurrent;
pred = localCurrent;
if (obj) {
var memPred = pred;
JIterator(json[child], pred);
pred = memPred;
}
}
if (this) {
current = root;
this.Level = 0;
}
}
JIterator.prototype.Current = function () { return current; }
JIterator.prototype.SetCurrent = function (newCurrent) {
current = newCurrent;
this.Level = 0;
while(newCurrent = newCurrent.parent) this.Level++;
}
JIterator.prototype.Parent = function () {
var retVal = current.parent;
if (retVal == null) return false;
this.Level--;
return current = retVal;
}
JIterator.prototype.Pred = function () {
var retVal = current.pred;
if (retVal == null) return false;
return current = retVal;
}
JIterator.prototype.Node = function () {
var retVal = current.node;
if (retVal == null) return false;
this.Level++;
return current = retVal;
}
JIterator.prototype.Next = function () {
var retVal = current.next;
if (retVal == null) return false;
return current = retVal;
}
JIterator.prototype.Key = function () { return current.key; }
JIterator.prototype.KeyDots = function () { return (typeof (current.key) == "number") ? "" : (current.key + ':'); }
JIterator.prototype.Value = function () { return current.value; }
JIterator.prototype.Reset = function () {
current = root;
this.Level = 0;
}
JIterator.prototype.RawPath = function () {
var steps = [], level = current;
do {
if (level != null && level.value instanceof Object) {
steps.push(level.key + (level.value instanceof Array ? "[]" : "{}"));
} else {
if (level != null) steps.push(level.key);
else break;
}
level = level.parent;
} while (level != null);
var retVal = "";
retVal = steps.reverse();
return retVal;
}
JIterator.prototype.Path = function (raw) {
var steps = [], level = current;
do {
if (level != null && level.value instanceof Object) {
var size = 0;
var items = level.node;
if (typeof (level.key) == "number" && !raw) steps.push('[' + level.key + ']');
else {
if(raw) {
if (typeof (level.key) != "number") steps.push(level.key);
} else {
while (items) {
size++;
items = items.next;
}
var type = (level.value instanceof Array ? "[]" : "{}");
var prev = steps[steps.length - 1];
if (prev && prev[0] == '[') {
var last = prev.length - 1;
if (prev[last] == ']') {
last--;
if (!isNaN(prev.substr(1, last))) {
steps.pop();
size += '.' + prev.substr(1, last);
}
}
}
steps.push(level.key + type[0] + size + type[1]);
}
}
} else {
if (level != null) {
if (typeof (level.key) == "number") steps.push('[' + level.key + ']');
else steps.push(level.key);
}
else break;
}
level = level.parent;
} while (level != null);
var retVal = "";
retVal = steps.reverse();
return retVal;
}
JIterator.prototype.DepthFirst = function () {
if (current == null) return 0; // exit sign
if (current.node != null) {
current = current.node;
this.Level++;
if (maxLevel < this.Level) maxLevel = this.Level;
return 1; // moved down
} else if (current.next != null) {
current = current.next;
return 2; // moved right
} else {
while (current != null) {
if (current.next != null) {
current = current.next;
return 3; // returned up & moved next
}
this.Level--;
current = current.parent;
}
}
return 0; // exit sign
}
JIterator.prototype.BreadthFirst = function () {
if (current == null) return 0; // exit sign
if (current.next) {
current = current.next;
return 1; // moved right
} else if (current.parent) {
var level = this.Level, point = current;
while (this.DepthFirst() && level != this.Level);
if (current) return 2; // returned up & moved next
do {
this.Reset();
level++;
while (this.DepthFirst() && level != this.Level);
if (current) return 3; // returned up & moved next
} while (maxLevel >= level);
return current != null ? 3 : 0;
} else if (current.node) {
current = current.node;
return 3;
} else if (current.pred) {
while (current.pred) current = current.pred;
while (current && !current.node) current = current.next;
if (!current) return null;
else return this.DepthFirst();
}
}
JIterator.prototype.ReadArray = function () {
var retVal = {};
var item = current;
do {
if (item.value instanceof Object) {
if (item.value.length == 0) retVal[item.key] = item.node;
else retVal[item.key] = item;
} else retVal[item.key] = item.value;
item = item.next;
} while (item != null);
return retVal;
}
JIterator.prototype.FindKey = function (key) {
var pos = current;
while (current && current.key != key) this.DepthFirst();
if (current.key == key) {
var retVal = current;
current = pos;
return retVal;
} else {
current = pos;
return null;
}
}
return JIterator;
})();
traverse(new JIterator(src));
Your short JSON version was different, now using this one, which looks like your required results (attrs changed and text moved from root under foo):
{
"foo": {
"bar": {
"type": "someType",
"id": "ga241ghs"
},
"tags": [
{
"#tagId": "123",
"tagAttributes": {
"attr1": "AAA",
"attr2": "111"
}
},
{
"#tagId": "456",
"tagAttributes": {
"attr1": "BBB",
"attr2": "222"
}
}
],
"text": "My text"
}
}
Figured it out how to do it with a Ruby filter directly in Logstash - for all searching for this in future, here is one example on how to do it for #tagId:
filter {
ruby { code => '
i = 0
tagId_array = Array.new
while i < event.get( "[foo][tags]" ).length do
tagId_array = tagId_array.push(event.get( "[foo][tags][" + i.to_s + "][#tagId]" ))
i += 1
end
event.set( "foo.tags.tagId", tagId_array )
'
}
}
I am trying to change the value of an HTML input based upon if a checkbox is checked. It works totally fine if I only reset one input, but if I try to reset two inputs at the same time I get the error
Cannot invoke an expression whose type lacks a call signature. Type 'String' has no compatible call signatures.
My code is as follows
if((<HTMLInputElement>unavailableInputs[i]).checked){
(<HTMLInputElement>qtyShippedInputs[i]).value = ""
(<HTMLInputElement>trackingNumberInputs[i]).value = ""
}
If I only reset one of the values, regardless of which one, it throws no errors and works totally fine. As soon as I do both qtyShipped and trackingNumber I get the error. In addition in the browser I get the error
"" is not a function
I appreciate any and all help.
As requested here is the whole code with a work around that solves the problem
disableFulfillment(shipment) {
const unavailableInputs = document.getElementsByClassName('unavailable-qty')
const qtyShippedInputs = document.getElementsByClassName('qty-shipped')
const requestedQtyFields = document.getElementsByClassName('requested-qty')
const trackingNumberInputs = document.getElementsByClassName('tracking-number')
const reasonCodeInputs = document.getElementsByClassName('reason-codes')
const reasonCodeValues = []
const lines = []
const lineCompleted = []
let i
for (i = 0; i < trackingNumberInputs.length; i++) {
if ((<HTMLInputElement>unavailableInputs[i]).checked) {
(<HTMLInputElement>qtyShippedInputs[i]).value = ''
}
if ((<HTMLInputElement>unavailableInputs[i]).checked) {
(<HTMLInputElement>trackingNumberInputs[i]).value = ''
}
if (!(<HTMLInputElement>unavailableInputs[i]).checked) {
if ((<HTMLInputElement>unavailableInputs[i]).nextElementSibling) {
(<HTMLInputElement>unavailableInputs[i].nextElementSibling.firstChild).value = ''
reasonCodeValues[i] = (<HTMLInputElement>reasonCodeInputs[i]).value
} else {
reasonCodeValues[i] = 0
}
} else {
if ((<HTMLInputElement>unavailableInputs[i]).nextElementSibling.firstElementChild) {
reasonCodeValues[i] = (<HTMLInputElement>unavailableInputs[i].nextElementSibling.firstElementChild).value
} else {
reasonCodeValues[i] = 0
}
}
const inputs = {
unavailable: (<HTMLInputElement>unavailableInputs[i]).checked,
qtyShipped: (<HTMLInputElement>qtyShippedInputs[i]).value,
requestedQty: (<HTMLInputElement>requestedQtyFields[i]).innerText,
reasonCodeInputs: reasonCodeValues[i],
trackingNumber: (<HTMLInputElement>trackingNumberInputs[i]).value
}
lines.push(inputs)
}
lines.forEach(line => {
if (line.unavailable === true && (line.reasonCodeInputs === 'CUSTOMERCANCEL' || line.reasonCodeInputs === 'UNAVAILABLE')) {
lineCompleted.push(true)
} else if (line.qtyShipped === line.requestedQty && line.trackingNumber.length >= 9) {
lineCompleted.push(true)
} else {
lineCompleted.push(false)
}
})
return !lineCompleted.every(function(e) {
return e === true
})
}
You will see the only change is that it is broken into two identical if statements. Which works no problem.
Here is the same code with the two setters placed inside the same if statement which breaks.
disableFulfillment(shipment) {
const unavailableInputs = document.getElementsByClassName('unavailable-qty')
const qtyShippedInputs = document.getElementsByClassName('qty-shipped')
const requestedQtyFields = document.getElementsByClassName('requested-qty')
const trackingNumberInputs = document.getElementsByClassName('tracking-number')
const reasonCodeInputs = document.getElementsByClassName('reason-codes')
const reasonCodeValues = []
const lines = []
const lineCompleted = []
let i
for (i = 0; i < trackingNumberInputs.length; i++) {
if ((<HTMLInputElement>unavailableInputs[i]).checked) {
(<HTMLInputElement>qtyShippedInputs[i]).value = ''
(<HTMLInputElement>trackingNumberInputs[i]).value = ''
}
if (!(<HTMLInputElement>unavailableInputs[i]).checked) {
if ((<HTMLInputElement>unavailableInputs[i]).nextElementSibling) {
(<HTMLInputElement>unavailableInputs[i].nextElementSibling.firstChild).value = ''
reasonCodeValues[i] = (<HTMLInputElement>reasonCodeInputs[i]).value
} else {
reasonCodeValues[i] = 0
}
} else {
if ((<HTMLInputElement>unavailableInputs[i]).nextElementSibling.firstElementChild) {
reasonCodeValues[i] = (<HTMLInputElement>unavailableInputs[i].nextElementSibling.firstElementChild).value
} else {
reasonCodeValues[i] = 0
}
}
const inputs = {
unavailable: (<HTMLInputElement>unavailableInputs[i]).checked,
qtyShipped: (<HTMLInputElement>qtyShippedInputs[i]).value,
requestedQty: (<HTMLInputElement>requestedQtyFields[i]).innerText,
reasonCodeInputs: reasonCodeValues[i],
trackingNumber: (<HTMLInputElement>trackingNumberInputs[i]).value
}
lines.push(inputs)
}
lines.forEach(line => {
if (line.unavailable === true && (line.reasonCodeInputs === 'CUSTOMERCANCEL' || line.reasonCodeInputs === 'UNAVAILABLE')) {
lineCompleted.push(true)
} else if (line.qtyShipped === line.requestedQty && line.trackingNumber.length >= 9) {
lineCompleted.push(true)
} else {
lineCompleted.push(false)
}
})
return !lineCompleted.every(function(e) {
return e === true
})
}
I am trying to work with Symfony2, Doctrine and Angujarjs. There is no problem with Symfony2 or Doctrine but I have issues using an ajax request with angularjs. Either it doesn't load anything and I did make a mistake while loading the json (json comes from Symfony and its working) or if it's working, but the json doesn't contain any of the relationship's data.
So, what's the correct way to
A: create a response for angularjs with relationship data (such as articles and categories)
B: load the requested json into an angularjs variable
Here is my controller.js
var app = angular.module("MyApp", []) .config(['$interpolateProvider', function ($interpolateProvider) {
$interpolateProvider.startSymbol('[[');
$interpolateProvider.endSymbol(']]');
}]);
app.filter('offset', function() {
return function(input, start) {
start = parseInt(start, 10);
return input.slice(start);
};
});
app.filter('htmlToPlaintext', function() {
return function(text) {
return String(text).replace(/<[^>]+>/gm, '');
};
});
app.controller("PaginationCtrl", function($scope, $http) {
$scope.articlesPerPage = 8;
$scope.currentPage = 0;
function htmlToPlaintext(text) {
return String(text).replace(/<[^>]+>/gm, '');
}
// this should load the json from '/admin/jsonallarticles' into the articles variable
$http.get('/admin/jsonallarticles').success(function(data) {
$scope.articles = data;
});
$scope.range = function() {
var rangeSize = 5;
var ret = [];
var start;
start = $scope.currentPage;
if ( start > $scope.pageCount()-rangeSize ) {
start = $scope.pageCount()-rangeSize+1;
}
for (var i=start; i<start+rangeSize; i++) {
ret.push(i);
}
return ret;
};
$scope.prevPage = function() {
if ($scope.currentPage > 0) {
$scope.currentPage--;
}
};
$scope.prevPageDisabled = function() {
return $scope.currentPage === 0 ? "disabled" : "";
};
$scope.pageCount = function() {
return Math.ceil($scope.articles.length/$scope.articlesPerPage)-1;
};
$scope.nextPage = function() {
if ($scope.currentPage < $scope.pageCount()) {
$scope.currentPage++;
}
};
$scope.nextPageDisabled = function() {
return $scope.currentPage === $scope.pageCount() ? "disabled" : "";
};
$scope.setPage = function(n) {
$scope.currentPage = n;
};
});
This is my symfony2 function
public function jsonallarticlesAction() {
$articles = $this->getDoctrine()
->getRepository('AcmeBlogBundle:Articles');
if ( !$articles ) {
throw $this->createNotFoundException(
'Keine Beiträge gefunden!');
}
$queryArticles = $articles->createQueryBuilder('a')
->where('a.status = :status')
->setParameter('status', 0)
->orderBy('a.createdDate', 'DESC')
->getQuery()
->getResult(\Doctrine\ORM\Query::HYDRATE_ARRAY);;
$articles = array_values($queryArticles);
$response = new Response();
$response->setContent(json_encode($articles));
$response->headers->set('Content-Type', 'application/json');
return $response;
}
EDITED CONTROLLER
I tried using the serializer which comes with Symfony
$encoders = array(new XmlEncoder(), new JsonEncoder());
$normalizers = array(new GetSetMethodNormalizer());
$serializer = new Serializer($normalizers, $encoders);
$articles = $this->getDoctrine()
->getRepository('AcmeBlogBundle:Articles')
->findAll();
if ( !$articles ) {
throw $this->createNotFoundException(
'Keine Artikel gefunden!');
}
$serializer->serialize($articles, 'json');
return new Response(json_encode($json));
But I receive an error:
A circular reference has been detected (configured limit: 1).
For work with Angular.js you must write Rest API. For this you can use https://github.com/FriendsOfSymfony/FOSRestBundle
And for serialize your entities with needed data use http://jmsyst.com/bundles/JMSSerializerBundle
It compatible with FOSRestBundle.
As example of use those bundles you can look one our project https://github.com/stfalcon-studio/lost-and-found
I ran into the same issue and it was due to the fact that my Entity was related back to the same entity from my second entity on a different field. I just simply created this function in my Entity:
public function removeRelationsThatCauseCircularError()
{
$this->companyEvents = NULL;
}
And run the function before going through the serializer.
I'm trying to update multiple fields of a row on a table on the database. I tried several solutions I found here in stackoverflow but no one had worked for me.
In this function, I give a feedback of a 'Product', and in the table Product I have 4 fields, called num_votes, num_negative_votes, num_neutral_votes and num_positive_votes.
When I call this function, i need to update this fields of the database depending on the value of the form.
How can I update 2 fields at the same time?
The solution I tried is this one: CakePHP - How to update multiple records
public function setFeedback($id = null) {
$this->autoRender = false;
if (!$id) {
$this->redirect(array('action' => 'index'));
}
else {
$product = $this->Product->findById($id);
$num_votes = $product['Product']['num_votes'] + 1;
if($this->request->data['Product']['num_points'] == "0") {
$num_negative_votes = $product['Product']['num_negative_votes'] + 1;
$arrayToSave = array(
'num_votes' => $num_votes,
'num_negative_votes' => $num_negative_votes);
$this->Product->saveMany($arrayToSave, array('deep' => true));
}
else if ($this->request->data == "1") {
$num_neutral_votes = $product['Product']['num_neutral_votes'] + 1;
$arrayToSave = array(
'num_votes' => $num_votes,
'num_neutral_votes' => $num_neutral_votes);
$this->Product->saveMany($arrayToSave, array('deep' => true));
}
else if ($this->request->data == "2 ") {
$num_positive_votes = $product['Product']['num_positive_votes'] + 1;
$arrayToSave = array(
'num_votes' => $num_votes,
'num_positive_votes' => $num_positive_votes);
$this->Product->saveMany($arrayToSave, array('deep' => true));
}
$this->redirect(array('action' => 'index'));
}
}
Try this-
public function setFeedback($id = null) {
$this->autoRender = false;
if (!$id) {
$this->redirect(array('action' => 'index'));
}
$product = $this->Product->findById($id);
$num_votes = $product['Product']['num_votes'] + 1;
if($this->request->data['Product']['num_points'] == "0") {
$num_negative_votes = $product['Product']['num_negative_votes'] + 1;
$arrayToSave['Product']['num_negative_votes'] = $num_negative_votes;
}
else if ($this->request->data == "1") {
$num_neutral_votes = $product['Product']['num_neutral_votes'] + 1;
$arrayToSave['Product']['num_neutral_votes'] = $num_neutral_votes;
}
else if ($this->request->data == "2 ") {
$num_positive_votes = $product['Product']['num_positive_votes'] + 1;
$arrayToSave['Product']['num_positive_votes'] = $num_positive_votes;
}
$arrayToSave['Product']['num_votes'] = $num_votes;
$this->Product->id = $id;
if($this->Product->save($arrayToSave)){
$this->redirect(array('action' => 'index'));
}else{
$this->Session->setFlash('Something is wrong.');
}
}
A simple function defined in the user-extensions.js :
Selenium.prototype.doGetThis = function(){
var errors = "";
if (browserVersion.isChrome) {
errors = true;
} else {
throw new SeleniumError("TODO: Non-FF browser...");
}
return errors;
}
The Selenium.java file:
String getThis() {
return this.commandProcessor.doCommand("getThis", EMPTY_STRING_ARRAY);
}
Running the test throws a SeleniumException:
CHECKPOINT-FAIL com.thoughtworks.selenium.SeleniumException: this.waitForCondition is not a function
Could this exception be avoided?
Settings:
selenium server 2.0a5
firefox 3.6.11
After I added the ; I still got the same exception.
Selenium.prototype.doGetThis = function(){
var errors = "";
if (browserVersion.isChrome) {
errors = true;
} else {
throw new SeleniumError("TODO: Non-FF browser...");
}
return errors;
};
It seems that you need to add a ; to the end of your doGetThis function:
Selenium.prototype.doGetThis = function(){
var errors = "";
if (browserVersion.isChrome) {
errors = true;
} else {
throw new SeleniumError("TODO: Non-FF browser...");
}
return errors;
};