Is there a one liner or how can I get all instances of a named list in any node?
say I get jason where multiple nodes could have a sub collection called "comments". How can I get all nodes that contain a collection of "comments"?
Thanks,
If you can provide an example of the JSON, I can give you a definitive answer.
However, I can post some of the JSON I'm parsing and you can see how it works and possibly shape it to fit your needs.
"abridged_cast": [
{
"name": "Clark Gable",
"characters": ["Rhett Butler"]
},
{
"name": "Vivien Leigh",
"characters": ["Scarlett O'Hara"]
},
{
"name": "Leslie Howard",
"characters": ["Ashley Wilkes"]
},
{
"name": "Olivia de Havilland",
"characters": ["Melanie Hamilton"]
},
{
"name": "Hattie McDaniel",
"characters": ["Mammy"]
}
],
Notice how abridged_cast is an array of values, and one value in that array (characters) is an array itself.
Here's how I fetch the data:
var castMembers = (JArray) x["abridged_cast"];
foreach (var castMember in castMembers)
{
CastMember member = new CastMember();
member.Actor = (string) castMember["name"];
var characters = (JArray) castMember["characters"];
foreach (var character in characters)
{
member.Characters.Add((string)character);
movie.Cast.Add(member);
}
}
Related
I need help with writing my consumer Pacts using pact-jvm (https://github.com/DiUS/pact-jvm).
My problem is I have a field which is a list (an array) of maps. Each map can have elements of different types (strings or sub-maps), eg.
"validatedAnswers": [
{
"type": "typeA",
"answers": {
"favourite_colour": "Blue",
"correspondence_address": {
"line_1": "Main St",
"postcode": "1A 2BC",
"town": "London"
}
}
},
{
"type": "typeB",
"answers": {
"first_name": "Firstname",
"last_name": "Lastname",
}
}
]
but we're only interested in some of those answers.
NOTE: The above is only an example showing the structure of validatedAnswers. Each answers map has dozens of elements.
What we really need is this: https://github.com/pact-foundation/pact-specification/issues/38, but it's planned for v.4. In the meantime we're trying a different approach. What I'm attempting to do now is to specify that each element of the list is a non-empty map. Another approach is to specify that each element of the list is not null. Can any of this be done using Groovy DSL?
This:
new PactBuilder().serviceConsumer('A').hasPactWith('B')
.port(findAvailablePort()).uponReceiving(...)
.willRespondWith(status: 200, headers: ['Content-Type': 'application/json'])
.withBody {
validatedAnswers minLike(1) {
type string()
answers {
}
}
}
doesn't work because it mean answers is expected to be empty ("Expected an empty Map but received Map( [...] )", see also https://github.com/DiUS/pact-jvm/issues/298).
So what I would like to do is something like this:
.withBody {
validatedAnswers minLike(1) {
type string()
answers Matchers.map()
}
}
or:
validatedAnswers minLike(1) {
type string()
answers {
keyLike 'title', notNull()
}
}
or:
validatedAnswers minLike(1) {
type string()
answers notNull()
}
Can it be done?
I would create two separate tests for this, one test for each of the different response shapes and have a provider state for each e.g. given there are type b answers.
This way when you verify on provider side, it will only send those two field types.
The union of the two examples gives a contract that allows both.
You can do it without DSL, sample Groovy script:
class ValidateAnswers {
static main(args) {
/* Array with some samples */
List<Map> answersList = [
[
type: 'typeA',
answers: [
favourite_colour: 'Blue',
correspondence_address: [
line_1: 'Main St',
postcode: '1A 2BC',
town: 'London'
]
]
],
[
type: 'typeB',
answers: [
first_name: 'Firstname',
last_name: "Lastname"
]
],
[
type: 'typeC',
answers: null
],
[
type: 'typeD'
],
[
type: 'typeE',
answers: [:]
]
]
/* Iterating through all elements in list above */
for (answer in answersList) {
/* Print result of checking */
println "$answer.type is ${validAnswer(answer) ? 'valid' : 'not valid'}"
}
}
/**
* Method to recursive iterate through Map's.
* return true only if value is not an empty Map and it key is 'answer'.
*/
static Boolean validAnswer(Map map, Boolean result = false) {
map.each { key, value ->
if (key == 'answers') {
result = value instanceof Map && value.size() > 0
} else if (value instanceof Map) {
validAnswer(value as Map, false)
}
}
return result
}
}
Output is:
typeA is valid
typeB is valid
typeC is not valid
typeD is not valid
typeE is not valid
I have a data structure in firebase
{
"name": "Sample",
"category": ["123456", "789012"]
}
The array of category contains ID which refers to documents in another collection. I can get the above document as Observable. What I really what as the end result is the below data structure
{
"name": "Sample"
"category": [
{
"name": "Category 1"
},
{
"name": "Category 2"
}
]
}
How can I bring this data? I don't think switchMap works for this. If so, can someone give an example of that?
You can try using flatMap and forkJoin. FlatMap allows you to chain multiple async requests together and forkJoin allows you to wait for all observables to return a value before continuing.
And you could wright something like this:
var finalData;
firstRequest('sample').flatMap((data) => {
// assuming data = { name: "Sample", catagory: [ "23123", "31321", ... ] }
finalData = data;
var observables = [];
data.catagory.forEach((c) => {
observable.push(secondRequest(c));
});
return forkJoin(observables);
}).flatMap((results) => {
// assuming results is an array like [ { name: "Catagory 1", ... } ]
finalData.category = results;
return finalData;
});
Can I scan DynamoDB by 'order.shortCode', in the given example. The console is indicating I can't with dot notation, and I can't find any documentation on it.
{
"key2": "cj11b1ygp0000jcgubpe5mso3",
"order": {
"amount": 74.22,
"dateCreated": "2017-04-02T19:15:33-04:00",
"orderNumber": "cj11b1ygp0000jcgubpe5mso3",
"shortCode": "SJLLDE"
},
"skey2": "SJLLDE"
}
To scan by a nested attribute, you should use ExpressionAttributeNames parameter to pass each path component (i.e. order and shortCode) separately into FilterExpression like shown below:
var params = {
TableName: 'YOUR_TABLE_NAME',
FilterExpression: "#order.#shortCode = :shortCodeValue",
ExpressionAttributeNames: {
'#order': 'order',
"#shortCode": "shortCode"
},
ExpressionAttributeValues: {
':shortCodeValue': 'SJLLDE'
}
};
dynamodbDoc.scan(params, function(err, data) {
});
Here is a link to documentation explaining this:
http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.ExpressionAttributeNames.html#Expressions.ExpressionAttributeNames.NestedAttributes
I have a custom class in ES 2.5 of the following:
Title
DataSources
Content
Running a search is fine, except with the middle field - it's built/indexed using a delimiter of '|'.
ex: "|4|7|8|9|10|12|14|19|20|21|22|23|29|30"
I need to build a query that matches some in all fields AND matches at least one number in the DataSource field.
So to summarize what I currently have:
QueryBase query = new SimpleQueryStringQuery
{
//DefaultOperator = !operatorOR ? Operator.And : Operator.Or,
Fields = LearnAboutFields.FULLTEXT,
Analyzer = "standard",
Query = searchWords.ToLower()
};
_boolQuery.Must = new QueryContainer[] {query};
That's the search words query.
foreach (var datasource in dataSources)
{
// Add DataSources with an OR
queryContainer |= new WildcardQuery { Field = LearnAboutFields.DATASOURCE, Value = string.Format("*{0}*", datasource) };
}
// Add this Boolean Clause to our outer clause with an AND
_boolQuery.Filter = new QueryContainer[] {queryContainer};
}
That's for the datasources query. There can be multiple datasources.
It doesn't work, and returns on results with the filter query added on. I think I need some work on the tokenizer/analyzer, but I don't know enough about ES to figure that out.
EDIT: Per Val's comments below I have attempted to recode the indexer like this:
_elasticClientWrapper.CreateIndex(_DataSource, i => i
.Mappings(ms => ms
.Map<LearnAboutContent>(m => m
.Properties(p => p
.String(s => s.Name(lac => lac.DataSources)
.Analyzer("classic_tokenizer")
.SearchAnalyzer("standard")))))
.Settings(s => s
.Analysis(an => an.Analyzers(a => a.Custom("classic_tokenizer", ca => ca.Tokenizer("classic"))))));
var indexResponse = _elasticClientWrapper.IndexMany(contentList);
It builds successfully, with data. However the query still isn't working right.
New query for DataSources:
foreach (var datasource in dataSources)
{
// Add DataSources with an OR
queryContainer |= new TermQuery {Field = LearnAboutFields.DATASOURCE, Value = datasource};
}
// Add this Boolean Clause to our outer clause with an AND
_boolQuery.Must = new QueryContainer[] {queryContainer};
And the JSON:
{"learnabout_index":{"aliases":{},"mappings":{"learnaboutcontent":{"properties":{"articleID":{"type":"string"},"content":{"type":"string"},"dataSources":{"type":"string","analyzer":"classic_tokenizer","search_analyzer":"standard"},"description":{"type":"string"},"fileName":{"type":"string"},"keywords":{"type":"string"},"linkURL":{"type":"string"},"title":{"type":"string"}}}},"settings":{"index":{"creation_date":"1483992041623","analysis":{"analyzer":{"classic_tokenizer":{"type":"custom","tokenizer":"classic"}}},"number_of_shards":"5","number_of_replicas":"1","uuid":"iZakEjBlRiGfNvaFn-yG-w","version":{"created":"2040099"}}},"warmers":{}}}
The Query JSON request:
{
"size": 10000,
"query": {
"bool": {
"must": [
{
"simple_query_string": {
"fields": [
"_all"
],
"query": "\"housing\"",
"analyzer": "standard"
}
}
],
"filter": [
{
"terms": {
"DataSources": [
"1"
]
}
}
]
}
}
}
One way to achieve this is to create a custom analyzer with a classic tokenizer which will break your DataSources field into the numbers composing it, i.e. it will tokenize the field on each | character.
So when you create your index, you need to add this custom analyzer and then use it in your DataSources field:
PUT my_index
{
"settings": {
"analysis": {
"analyzer": {
"number_analyzer": {
"type": "custom",
"tokenizer": "number_tokenizer"
}
},
"tokenizer": {
"number_tokenizer": {
"type": "classic"
}
}
}
},
"mappings": {
"my_type": {
"properties": {
"DataSources": {
"type": "string",
"analyzer": "number_analyzer",
"search_analyzer": "standard"
}
}
}
}
}
As a result, if you index the string "|4|7|8|9|10|12|14|19|20|21|22|23|29|30", you DataSources field will effectively contain the following array of token: [4, 7, 8, 9, 10, 12, 14, 191, 20, 21, 22, 23, 29, 30]
Then you can get rid of your WildcardQuery and simply use a TermsQuery instead:
terms = new TermsQuery {Field = LearnAboutFields.DATASOURCE, Terms = dataSources }
// Add this Boolean Clause to our outer clause with an AND
_boolQuery.Filter = new QueryContainer[] { terms };
At an initial glance at your code I think one problem you might have is that any queries placed within a filter clause will not be analysed. So basically the value will not be broken down into tokens and will be compared in its entirety.
It's easy to forget this so any values that require analysis need to be placed in the must or should clauses.
I want to save all data of a form.
My form has these elements-
( Using Postman Plugin )
My controller is like this-
[HttpPost]
public async Task<IActionResult> Insert(IFormCollection data)
{
return Ok(data);
}
So, I am getting something like this-
[
{
"key": "user_id",
"value": [
"'12'"
]
},
{
"key": "title",
"value": [
"123"
]
},
{
"key": "text[]",
"value": [
"werwer",
"ghj"
]
}
]
I want to get the value of texts.
So, for this case-
"werwer",
"ghj"
So, I have tried something like this-
foreach (string description in data["text"])
{
// description => empty
}
and also tried this-
data.text
and also-
data->text
But nothing works for me.
Can anyone please help?
Thanks in advance for helping.
Why not loop through each keys and if the key is "text", get the values. Since the value is a comma seperated string, you can call the Split method on that to get an array which contains 2 items( from your sample input).
foreach (string description in data.Keys)
{
if (description.Equals("text"))
{
var v = data[description];
var stringItems = v.Split(',');
foreach (var stringItem in stringItems)
{
//do something with stringItem
}
}
}
BTW, the key should be text, not text[]. Even if you have muliple input fields with the same name "text", when you submit, It will be a single key ("text") with 2 items int he value property
{
"key": "text",
"value": [
"werwer",
"ghj"
]
}