Check if null or empty in jolt and put another value which is present in input JSON - jolt

This is my input JSON:
{
"AddressBilling": {
"FirstName": "Some Name",
"LastName": "Some Name",
"Address":"some address"
}
"AddressShipping": {
"FirstName": "",
"LastName": "",
"Address":""
}
}
I want to keep "AddressBilling" and "AddressShipping" but with different names i:e "payment_address" and "shipping_address", for which i have written a spec file for payment_address" part
{
"operation": "shift",
"spec": {
"AddressBilling": {
"FirstName": "payment_address.firstname",
"LastName": "payment_address.lastname",
"Address": "payment_address.address"
},
"AddressShipping": {
"FirstName": "shipping_address.firstname",
"LastName": "shipping_address.lastname"
}
}
}
Now what I want is to check if "Address" key in "AddressShipping" object is null then i want to copy "Address" of "AddressBilling" to "Address" of "shipping_address".

Can do that with "modify-default". Modify-default will only fill in a value if a key does not exist or it's value is null.
Spec
[
{
"operation": "modify-default-beta",
"spec": {
"shipping_address": {
"address": "#(2,payment_address.address)"
}
}
}
]
Input A, where there is not shipping address
{
"payment_address": {
"address": "some address"
},
"shipping_address": {}
}
Produces output A, where the billing address is copied over
{
"payment_address" : {
"address" : "some address"
},
"shipping_address" : {
"address" : "some address"
}
}
Input B, where there is a shipping_address
{
"payment_address": {
"address": "some address"
},
"shipping_address": {
"address": 1234
}
}
Produces output B, where the shipping address does not get overwritten.
{
"payment_address" : {
"address" : "some address"
},
"shipping_address" : {
"address" : 1234
}
}

Related

Updating array list in Mongo DB

I want to update the Status field inside array list of Slots where id = "".
Sample data
{
"_id": ObjectId("621e816e7a938400016c5c64"),
"Resource": "abc#gmail.com",
"School": {
"Class": [
{
"Type": "ABC",
"Slots": [
{
"id": "",
"Duration": "1 week",
"Status": "Released",
"Selected": true
},
{
"id": "123",
"Duration": "1 week",
"Status": "Released",
"Selected": true
}
]
}
]
}
}
This is how I am approaching:
db.getCollection("XYZ").update({
"Resource": "abc#gmail.com",
"School.Class": {
"$elemMatch": {
"Type": "ABC",
"Slots.Status": "Released",
"Slots.id": "",
"Slots.Duration": "1 week"
}
}
},
{
$set: {
"School.Class.$[outer].Slots.$[inner].Status": "Confirmed"
}
},
{
"arrayFilters": [
{
"outer.Type": "ABC"
},
{
"inner.Duration": "1 week"
}
]
})
But it is updating the status as confirmed for the both the array list.How can I update the particular field where "Slots.id" : "" . Please forgive me in case of any misalignment or brackets missing in data
If I've understood correctly you are almost there, since you want to update only values where id is "" you have to add that condition into arrayFilters: "inner.id": "".
db.collection.update({
"Resource": "abc#gmail.com",
"School.Class": {
"$elemMatch": {
"Type": "ABC",
"Slots.Status": "Released",
"Slots.id": "",
"Slots.Duration": "1 week"
}
}
},
{
$set: {
"School.Class.$[outer].Slots.$[inner].Status": "Confirmed"
}
},
{
"arrayFilters": [
{
"outer.Type": "ABC"
},
{
"inner.Duration": "1 week",
"inner.id": "" // <--- This line
}
]
})
Example here

In elastic we have copy_to parameter for copying the fields. Is there any way to replicate the same in mongodb while indexing?

{
"global_string_mv": {
"match_mapping_type": "string",
"match": "global*_string_mv",
"mapping": {
"type": "text",
"copy_to": "global_fields_string_mv",
"fields": {
"text_en": {
"type": "text",
"analyzer": "text_en_index",
"search_analyzer": "text_en_query"
},
"text_en_shingle": {
"type": "text",
"analyzer": "text_shingle_en_index",
"search_analyzer": "text_shingle_en_query"
},
"keyword": {
"type": "keyword"
}
}
}
}
}
In elastic we have copy_to parameter for copying the fields.
Is there any way to replicate the same in mongodb while indexing????
UPDATE :-
PUT my-index-000001
{
"mappings": {
"properties": {
"first_name": {
"type": "text",
"copy_to": "full_name"
},
"last_name": {
"type": "text",
"copy_to": "full_name"
},
"full_name": {
"type": "text"
}
}
}
}
PUT my-index-000001/_doc/1
{
"first_name": "John",
"last_name": "Smith"
}
GET my-index-000001/_search
{
"query": {
"match": {
"full_name": {
"query": "John Smith",
"operator": "and"
}
}
}
}
The values of the first_name and last_name fields are copied to the full_name field.
The first_name and last_name fields can still be queried for the first name and last name respectively, but the full_name field can be queried for both first and last names.
In Elasticsearch, the copy_to parameter allows you to copy the values of multiple fields into a group field, which can then be queried as a single field.
Similarly we need to know that is this possible from mongodb ??
If it is possible then how ??
For more details refer to below link :-
https://www.elastic.co/guide/en/elasticsearch/reference/current/copy-to.html

Multifield wildcard search in ElasticSearch

Consider this very basic T-SQL query:
select * from Users
where FirstName like '%dm0e776467#mail.com%'
or LastName like '%dm0e776467#mail.com%'
or Email like '%dm0e776467#mail.com%'
How can I write this in Lucene?
I have tried the following:
The query way (does not work at all, no results):
{
"query": {
"bool": {
"should": [
{
"wildcard": {
"firstName": "dm0e776467#mail.com"
}
},
{
"wildcard": {
"lastName": "dm0e776467#mail.com"
}
},
{
"wildcard": {
"email": "dm0e776467#mail.com"
}
}
]
}
}
}
The Multimatch way (returns anything where mail.com is present)
{
"query": {
"multi_match": {
"query": "dm0e776467#mail.com",
"fields": [
"firstName",
"lastName",
"email"
]
}
}
}
A third attempt (returns expected result, but if I only insert "mail", then no results are returned)
{
"query": {
"query_string": {
"query": ""dm0e776467#mail.com"",
"fields": [
"firstName",
"lastName",
"email"
],
"default_operator": "or",
"allow_leading_wildcard": true
}
}
}
It seems to me as there is no way to force Elasticsearch to force a query to use the input string as ONE substring?
The standard (default) analyzer will tokenize this email as follows:
GET _analyze
{
"text": "dm0e776467#mail.com",
"analyzer": "standard"
}
yielding
{
"tokens" : [
{
"token" : "dm0e776467",
...
},
{
"token" : "mail.com",
...
}
]
}
This explains why the multi-match works with any *mail.com suffix and why the wildcards are failing.
I suggest the following modifications to your mapping, inspired by this answer:
PUT users
{
"settings": {
"analysis": {
"filter": {
"email": {
"type": "pattern_capture",
"preserve_original": true,
"patterns": [
"([^#]+)",
"(\\p{L}+)",
"(\\d+)",
"#(.+)",
"([^-#]+)"
]
}
},
"analyzer": {
"email": {
"tokenizer": "uax_url_email",
"filter": [
"email",
"lowercase",
"unique"
]
}
}
}
},
"mappings": {
"properties": {
"email": {
"type": "text",
"analyzer": "email"
},
"firstName": {
"type": "text",
"fields": {
"as_email": {
"type": "text",
"analyzer": "email"
}
}
},
"lastName": {
"type": "text",
"fields": {
"as_email": {
"type": "text",
"analyzer": "email"
}
}
}
}
}
}
Note that I've used .as_email fields on your first- & lastName fields -- you may not want to force them to be mapped as emails by default.
Then after indexing a few samples:
POST _bulk
{"index":{"_index":"users","_type":"_doc"}}
{"firstName":"abc","lastName":"adm0e776467#mail.coms","email":"dm0e776467#mail.com"}
{"index":{"_index":"users","_type":"_doc"}}
{"firstName":"xyz","lastName":"opr","email":"dm0e776467#mail.com"}
{"index":{"_index":"users","_type":"_doc"}}
{"firstName":"zyx","lastName":"dm0e776467#mail.com","email":"qwe"}
{"index":{"_index":"users","_type":"_doc"}}
{"firstName":"abc","lastName":"efg","email":"ijk"}
the wildcards are working perfectly fine:
GET users/_search
{
"query": {
"bool": {
"should": [
{
"wildcard": {
"email": "dm0e776467#mail.com"
}
},
{
"wildcard": {
"lastName.as_email": "dm0e776467#mail.com"
}
},
{
"wildcard": {
"firstName.as_email": "dm0e776467#mail.com"
}
}
]
}
}
}
Do check how this tokenizer works under the hood to prevent 'surprising' query results:
GET users/_analyze
{
"text": "dm0e776467#mail.com",
"field": "email"
}

Loopback belongsTo relation with MongoDB giving Error 400

In my MongoDB database, I have this data :
In a User collection :
{
"_id" : ObjectId("5a2c725621691170792fbc3e"),
"username" : "username",
"email" : "test#gmail.com"
}
In a Content Collection :
{
"_id" : ObjectId("5a2c7857b4f9e44a4d618bfd"),
"title" : "Article title",
"author" : ObjectId("5a2c725621691170792fbc3e")
}
So I've made 2 models in Loopback with a relation hasMany/belongsTo :
{
"name": "user",
...
"properties": {
"username": {
"type": "string",
"required": true
},
"email": {
"type": "string",
"required": true
}
},
"relations": {
"contents": {
"type": "hasMany",
"model": "content",
"foreignKey": "author"
}
}
}
Content has an author :
{
"name": "content",
"properties": {
"title": {
"type": "string",
"required": true
}
},
"relations": {
"author": {
"type": "belongsTo",
"model": "user",
"foreignKey": "author"
}
},
}
So that's great, Loopback give me those URLS :
/users/{id}/contents to get Contents of an user, it's working fine
/contents/{id}/author
to get the Author of a content, but this one give me an error :
400 Key mismatch: content.author: function () { [native code] },
user.id: 5a2c725621691170792fbc3e
I can't figure out what's wrong, thanks !
I set up an empty project and added models and relations like described and it works to get contents through user and user through content.
In you example data I see that author in content has a different value than id in user. Is that a typo in the question here or in the actual data?
"_id" : ObjectId("5a2c725621691170792fbc3e")
"author" : ObjectId("5a2c7af721691170792fbfd3")

I have a simple json file that I'm trying to transform using jolt and having trouble with it since I'm very new to jolt

Here's what I want to do:
1. Concatenate first and last name with name
2. Change id to employeeID and add prefix with employee ID: emp_id
3. If department is equal to sales, than department should be "SL"
4. If department is equal to sales, than department should be "RET"
Here's my input:
{
"employees": [{
"f_name": "tom",`
"l_name": "smith",
"id": "100",
"department": "sales",
"company": "ABC Intelligence"
},
{
"f_name": "john",
"l_name": "doe",
"id": "102",
"department": "returns",
"company": "ABC Intelligence"
}, {
"f_name": "jane",
"l_name": "doe",
"id": "103",
"department": "sales",
"company": "ABC Intelligence"
}
]
}
specs:
[{
"operation": "shift",
"spec": {
"employees": {
"*": {
"name": "=concat(#(1,f_name),' ',#(1,l_name))"
}
}
}
},
{
"operation": "remove",
"spec": {
"employees": {
"*": {
"f_name": "",
"l_name": ""
}
}
}
}
]
desired output:
{
"employees": [
{
"name": "tom smith",
"employeeID": "emp_100",
"department": "SL",
"company": "ABC Intelligence"
},
{
"name": "john doe",
"employeeID": "emp_102",
"department": "RET",
"company": "ABC Intelligence"
},
{
"name": "jane doe",
"employeeID": "emp_103",
"department": "SL",
"company": "ABC Intelligence"
}
]
}
I was able to get the first rule but still struggling with the others. Any help would be appreciated
Spec
[
{
"operation": "modify-default-beta",
"spec": {
// add the mapping of department name to code, so we can use it later
"deptMap": {
"sales": "SL",
"returns": "RET"
},
"employees": {
"*": {
// build the fullName from the first and last names
"name": "=concat(#(1,f_name),' ',#(1,l_name))",
// build the employeeID
"employeeID": "=concat(emp_,#(1,id))"
}
}
}
},
{
"operation": "shift",
"spec": {
"employees": {
"*": { // employees arrays
// pass name, company, and employeeID thru
"name": "employees[&1].name",
"company": "employees[&1].company",
"employeeID": "employees[&1].employeeID",
// lookup the deparment code
"department": {
"*": { // value of dept
// got up 5 levels, come back down the deptMap
"#(4,deptMap.&)": "employees[&3].department"
}
}
}
}
}
}
]