Elasticsearch on fashion commerce - node.js

I have the following dataset indexed in elasticsearch
[
{
"id": "1",
"name": "Red T-shirt",
"size": "S",
"styleId": "R-1"
},
{
"id": "2",
"name": "Red T-shirt",
"size": "M",
"styleId": "R-1"
},
{
"id": "3",
"name": "Red T-shirt",
"size": "L",
"styleId": "R-1"
},
{
"id": "4",
"name": "White T-shirt",
"size": "S",
"styleId": "W-1"
},
{
"id": "5",
"name": "White T-shirt",
"size": "XL",
"styleId": "W-1"
}
]
In search result I want products grouped by styleId. Is it possible like bellow sample result? In most of the commerce websites like Amazon, Myntra, Flipkart I have seen they are doing the same what I am trying. I have tried many elasticsearch concepts like "collapse" but without success. Using kibana, and elasticsearch version 7.4. Any suggestions will be highly appreciated.
[
{
"id": "1",
"name": "Red T-shirt",
"size": "S",
"styleId": "R-1",
"sizes": [
{
"id": "2",
"name": "Red T-shirt",
"size": "M",
"styleId": "R-1"
},
{
"id": "3",
"name": "Red T-shirt",
"size": "L",
"styleId": "R-1"
}
]
},
{
"id": "4",
"name": "White T-shirt",
"size": "S",
"styleId": "W-1",
"sizes": [
{
"id": "5",
"name": "White T-shirt",
"size": "XL",
"styleId": "W-1"
}
]
},
]

You can use collapse with cardinality aggregation.
Cardinality will give group level count
{
"_source": "false",
"collapse": {
"field": "styleId.keyword",
"inner_hits": {
"name": "group-details",
"size": 5
}
},
"from": 0,
"size": 5,
"aggs": {
"type_count": {
"cardinality": {
"field": "styleId.keyword"
}
}
}
}

Related

Multi-Level grouping aggregate with MongoDB

I have project we are working for, and I have chart of account built with multi-level parent/children
ex.
[
{
"_id": "6339dc11de91f060af6e17e0",
"name": "Cash",
"code": "1",
"codeChain": "1",
"isParent": true
},
{
"_id": "6339dc11de91f060af6e17e1",
"parent": "6339dc11de91f060af6e17e0",
"name": "Cash",
"code": "01",
"codeChain": "1.01",
"isParent": true
},
{
"_id": "6339dc11de91f060af6e17e2",
"parent": "6339dc11de91f060af6e17e1",
"name": "Cash",
"code": "001",
"codeChain": "1.01.001",
"isParent": true
},
{
"_id": "6339dc11de91f060af6e17e3",
"parent": "6339dc11de91f060af6e17e2",
"name": "Cash",
"code": "001",
"codeChain": "1.01.001.001",
"isParent": true
}
// and so on
]
then we need to make a query to get the result of :
[
{
"_id": "6339dc11de91f060af6e17e0",
"name": "Cash",
"code": "1",
"codeChain": "1",
"isParent": true,
"children": [
{
{
"_id": "6339dc11de91f060af6e17e1",
"parent": "6339dc11de91f060af6e17e0",
"name": "Cash",
"code": "01",
"codeChain": "1.01",
"isParent": true,
"children": [
{
"_id": "6339dc11de91f060af6e17e2",
"parent": "6339dc11de91f060af6e17e1",
"name": "Cash",
"code": "001",
"codeChain": "1.01.001",
"isParent": true,
"children": [
{
"_id": "6339dc11de91f060af6e17e3",
"parent": "6339dc11de91f060af6e17e2",
"name": "Cash",
"code": "001",
"codeChain": "1.01.001.001",
"isParent": true
}
]
}
]
}
}
]
}
// and so on
]
NOTED THAT : We don't know how deep it could be, and also we have other collections with the transactions we will link it later
Or should we change all the data structure to serve that need !

How to filter the response from mongoDB, so nested arrays will include only items that meet a condition?

My documents look like this
{
"_id": {
"$oid": "62825f71005ce00c5f0235c1"
},
"user": "jon",
"roles": {
"User": 2001,
},
"STOCK ": [
{
"sku": "BLACK-M",
"productname": "BLACK",
"sendout": 0,
"recived": 1,
"totalinstock": 40,
"location": "B32",
"_id": {
"$oid": "62826016005ce00c5f0235c8"
}
},
{
"sku": "CJNS",
"productname": "89796363",
"sendout": 0,
"recived": 45,
"totalinstock": 0,
"location": "B232",
"_id": {
"$oid": "62836f2d56b4f1ac79c99b8d"
}
}
],
"ORDERS": [
{
"date": {
"$date": "2022-06-02T15:23:58Z"
},
"OrderNumber": "745607",
"City": "xxxxx",
"Address": "yyyyyy",
"Phone": "8678678678",
"Name": "Holly ",
"Trackingnumber": 40,
"ZipCode": 00000,
"Province": "New ",
"Quantity": [
1
],
"Product_Name": [
" pants pants"
],
"SKU": [
"CJNS"
],
"_id": {
"$oid": "6298d61ba6eeec72b78332a7"
}
},
{
"date": {
"$date": "2022-06-02T15:23:58Z"
},
"OrderNumber": "748840",
"City": "xxxxx",
"Address": "yyyyyy",
"Phone": "354353454",
"Name": "Michael",
"Trackingnumber": 0,
"ZipCode": 00000,
"Province": "North",
"Quantity": [
1
],
"Product_Name": [
" pants pants"
],
"SKU": [
"CJNS"
],
"_id": {
"$oid": "6298d61ba6eeec72b78332a9"
}
}
]
}
I successful to return all the objects in STOCK or all the objects in ORDERS
Through this query
const foundUser= await User.find({"user":req.body.user},("Orders") ).exec()
Now I want to filter the response to include only items where "Trackingnumber" is different from 0
For the sample data I expect to receive only
{
"date": {
"$date": "2022-06-02T15:23:58Z"
},
"OrderNumber": "748840",
"City": "xxxxx",
"Address": "yyyyyy",
"Phone": "354353454",
"Name": "Michael",
"Trackingnumber": 0,
"ZipCode": 00000,
"Province": "North",
"Quantity": [
1
],
"Product_Name": [
" pants pants"
],
"SKU": [
"CJNS"
],
"_id": {
"$oid": "6298d61ba6eeec72b78332a9"
}
}
You can use an aggregation pipeline with a $filter for this:
db.collection.aggregate([
{
$match: {
"user": "jon"
}
},
{
$project: {
ORDERS: {
$filter: {
input: "$ORDERS",
as: "item",
cond: {$ne: ["$$item.Trackingnumber", 0]}
}
}
}
}
])
Playground example
User.find({"Orders" : {"Trackingnumber": 0} })

How to setup Partial Authentication using Authorize API

Okay I am setting up Partial Payments via the Authorize.net API in order to enable multiple cards to be used to cover a single balance/charge.
I'm assuming thier Partial Auth feature covers my use case, but in testing, there is an issue I can show you using the API live console here: https://developer.authorize.net/api/reference/index.html#payment-transactions-charge-a-credit-card
Go to the link above and authorize partial payments with the request I edited below and you will notice when you press submit you get a splitTenderId:
{
"createTransactionRequest": {
"merchantAuthentication": {
"name": "5KP3u95bQpv",
"transactionKey": "346HZ32z3fP4hTG2"
},
"refId": "123456",
"transactionRequest": {
"transactionType": "authCaptureTransaction",
"amount": "462.25",
"payment": {
"creditCard": {
"cardNumber": "5424000000000015",
"expirationDate": "2020-12",
"cardCode": "999"
}
},
"lineItems": {
"lineItem": {
"itemId": "1",
"name": "vase",
"description": "Cannes logo",
"quantity": "18",
"unitPrice": "45.00"
}
},
"tax": {
"amount": "4.26",
"name": "level2 tax name",
"description": "level2 tax"
},
"duty": {
"amount": "8.55",
"name": "duty name",
"description": "duty description"
},
"shipping": {
"amount": "4.26",
"name": "level2 tax name",
"description": "level2 tax"
},
"poNumber": "456654",
"customer": {
"id": "99999456654"
},
"billTo": {
"firstName": "Ellen",
"lastName": "Johnson",
"company": "Souveniropolis",
"address": "14 Main Street",
"city": "Pecan Springs",
"state": "TX",
"zip": "44628",
"country": "USA"
},
"shipTo": {
"firstName": "China",
"lastName": "Bayles",
"company": "Thyme for Tea",
"address": "12 Main Street",
"city": "Pecan Springs",
"state": "TX",
"zip": "44628",
"country": "USA"
},
"customerIP": "192.168.1.1",
"transactionSettings": {
"setting": [
{
"settingName": "emailCustomer",
"settingValue": "true"
}, {
"settingName": "allowPartialAuth",
"settingValue": "true"
},
]
},
"userFields": {
"userField": [
{
"name": "MerchantDefinedFieldName1",
"value": "MerchantDefinedFieldValue1"
},
{
"name": "favorite_color",
"value": "blue"
}
]
}
}
}
}
This is only successful because the amount is 462.25 as the docs say to use for testing, if I use any other (real) amount the splitTenderId is not there.
Here is a new example request, you can post this again on the link above:
{
"createTransactionRequest": {
"merchantAuthentication": {
"name": "5KP3u95bQpv",
"transactionKey": "346HZ32z3fP4hTG2"
},
"refId": "123456",
"transactionRequest": {
"transactionType": "authCaptureTransaction",
"amount": "462",
"payment": {
"creditCard": {
"cardNumber": "5424000000000015",
"expirationDate": "2020-12",
"cardCode": "999"
}
},
"lineItems": {
"lineItem": {
"itemId": "1",
"name": "vase",
"description": "Cannes logo",
"quantity": "18",
"unitPrice": "45.00"
}
},
"tax": {
"amount": "4.26",
"name": "level2 tax name",
"description": "level2 tax"
},
"duty": {
"amount": "8.55",
"name": "duty name",
"description": "duty description"
},
"shipping": {
"amount": "4.26",
"name": "level2 tax name",
"description": "level2 tax"
},
"poNumber": "456654",
"customer": {
"id": "99999456654"
},
"billTo": {
"firstName": "Ellen",
"lastName": "Johnson",
"company": "Souveniropolis",
"address": "14 Main Street",
"city": "Pecan Springs",
"state": "TX",
"zip": "44628",
"country": "USA"
},
"shipTo": {
"firstName": "China",
"lastName": "Bayles",
"company": "Thyme for Tea",
"address": "12 Main Street",
"city": "Pecan Springs",
"state": "TX",
"zip": "44628",
"country": "USA"
},
"customerIP": "192.168.1.1",
"transactionSettings": {
"setting": [
{
"settingName": "emailCustomer",
"settingValue": "true"
}, {
"settingName": "allowPartialAuth",
"settingValue": "true"
},
]
},
"userFields": {
"userField": [
{
"name": "MerchantDefinedFieldName1",
"value": "MerchantDefinedFieldValue1"
},
{
"name": "favorite_color",
"value": "blue"
}
]
}
}
}
}
And with the 462 amount entered this is no longer a partial auth payment and I no longer get a splitTenderId.
Can someone please help me figure out what is going on?

search json file with python script

I have following tfstate file (it has JSON structure)
{
"version": 3,
"terraform_version": "0.11.1",
"serial": 1,
"lineage": "4d050905-8f3d-46df-8bbb-8859c708abe7",
"modules": [
{
"path": [
"root"
],
"outputs": {
"id": {
"sensitive": false,
"type": "list",
"value": [
"34.244.138.72",
"34.249.95.222"
]
}
},
"resources": {
"aws_instance.win-example.0": {
"type": "aws_instance",
"depends_on": [
"aws_security_group.DJukes"
],
"primary": {
"id": "i-0f8c0fcb36f58947d",
"attributes": {
"ami": "ami-cc821eb5",
"associate_public_ip_address": "true",
"availability_zone": "eu-west-1a",
"disable_api_termination": "false",
"ebs_block_device.#": "0",
"ebs_optimized": "false",
"ephemeral_block_device.#": "0",
"iam_instance_profile": "",
"id": "i-0f8c0fcb36f58947d",
"instance_state": "running",
"instance_type": "t2.medium",
"ipv6_addresses.#": "0",
"key_name": "",
"monitoring": "false",
"network_interface.#": "0",
"network_interface_id": "eni-8dbf17be",
"placement_group": "",
"primary_network_interface_id": "eni-8dbf17be",
"private_dns": "ip-172-31-30-138.eu-west-1.compute.internal",
"private_ip": "172.31.30.138",
"public_dns": "ec2-34-244-138-72.eu-west-1.compute.amazonaws.com",
"public_ip": "34.244.138.72",
"root_block_device.#": "1",
"root_block_device.0.delete_on_termination": "true",
"root_block_device.0.iops": "100",
"root_block_device.0.volume_id": "vol-0dcfa45e001323eac",
"root_block_device.0.volume_size": "30",
"root_block_device.0.volume_type": "gp2",
"security_groups.#": "1",
"security_groups.4272775738": "DJukes",
"source_dest_check": "true",
"subnet_id": "subnet-5b50a512",
"tags.%": "1",
"tags.Name": "DJukes-1",
"tenancy": "default",
"user_data": "fad67bb12b32d15c3f5156bf7bdd830d4e084c6f",
"volume_tags.%": "0",
"vpc_security_group_ids.#": "1",
"vpc_security_group_ids.2187737336": "sg-fd5adf87"
},
"meta": {
"e2bfb730-ecaa-11e6-8f88-34363bc7c4c0": {
"create": 600000000000,
"delete": 600000000000,
"update": 600000000000
},
"schema_version": "1"
},
"tainted": false
},
"deposed": [],
"provider": "provider.aws"
},
"aws_instance.win-example.1": {
"type": "aws_instance",
"depends_on": [
"aws_security_group.DJukes"
],
"primary": {
"id": "i-0bb714a7ddd376599",
"attributes": {
"ami": "ami-cc821eb5",
"associate_public_ip_address": "true",
"availability_zone": "eu-west-1a",
"disable_api_termination": "false",
"ebs_block_device.#": "0",
"ebs_optimized": "false",
"ephemeral_block_device.#": "0",
"iam_instance_profile": "",
"id": "i-0bb714a7ddd376599",
"instance_state": "running",
"instance_type": "t2.medium",
"ipv6_addresses.#": "0",
"key_name": "",
"monitoring": "false",
"network_interface.#": "0",
"network_interface_id": "eni-dab018e9",
"placement_group": "",
"primary_network_interface_id": "eni-dab018e9",
"private_dns": "ip-172-31-24-177.eu-west-1.compute.internal",
"private_ip": "172.31.24.177",
"public_dns": "ec2-34-249-95-222.eu-west-1.compute.amazonaws.com",
"public_ip": "34.249.95.222",
"root_block_device.#": "1",
"root_block_device.0.delete_on_termination": "true",
"root_block_device.0.iops": "100",
"root_block_device.0.volume_id": "vol-079b3491295b06249",
"root_block_device.0.volume_size": "30",
"root_block_device.0.volume_type": "gp2",
"security_groups.#": "1",
"security_groups.4272775738": "DJukes",
"source_dest_check": "true",
"subnet_id": "subnet-5b50a512",
"tags.%": "1",
"tags.Name": "DJukes-2",
"tenancy": "default",
"user_data": "fad67bb12b32d15c3f5156bf7bdd830d4e084c6f",
"volume_tags.%": "0",
"vpc_security_group_ids.#": "1",
"vpc_security_group_ids.2187737336": "sg-fd5adf87"
},
"meta": {
"e2bfb730-ecaa-11e6-8f88-34363bc7c4c0": {
"create": 600000000000,
"delete": 600000000000,
"update": 600000000000
},
"schema_version": "1"
},
"tainted": false
},
"deposed": [],
"provider": "provider.aws"
},
"aws_security_group.DJukes": {
"type": "aws_security_group",
"depends_on": [],
"primary": {
"id": "sg-fd5adf87",
"attributes": {
"description": "Managed by Terraform",
"egress.#": "1",
"egress.482069346.cidr_blocks.#": "1",
"egress.482069346.cidr_blocks.0": "0.0.0.0/0",
"egress.482069346.description": "",
"egress.482069346.from_port": "0",
"egress.482069346.ipv6_cidr_blocks.#": "0",
"egress.482069346.prefix_list_ids.#": "0",
"egress.482069346.protocol": "-1",
"egress.482069346.security_groups.#": "0",
"egress.482069346.self": "false",
"egress.482069346.to_port": "0",
"id": "sg-fd5adf87",
"ingress.#": "1",
"ingress.2601213444.cidr_blocks.#": "1",
"ingress.2601213444.cidr_blocks.0": "0.0.0.0/0",
"ingress.2601213444.description": "",
"ingress.2601213444.from_port": "0",
"ingress.2601213444.ipv6_cidr_blocks.#": "0",
"ingress.2601213444.protocol": "tcp",
"ingress.2601213444.security_groups.#": "0",
"ingress.2601213444.self": "false",
"ingress.2601213444.to_port": "6556",
"name": "DJukes",
"owner_id": "520150089049",
"revoke_rules_on_delete": "false",
"tags.%": "1",
"tags.Name": "allow-RDP",
"vpc_id": "vpc-8b23ccec"
},
"meta": {
"schema_version": "1"
},
"tainted": false
},
"deposed": [],
"provider": "provider.aws"
}
},
"depends_on": []
}
]
I want to extract public IP addresses to variables using python
"value": [
"34.244.138.72",
"34.249.95.222"
]
So far, i have following code:
#!/bin/python
import json
import os.path
import shutil
from os import mkdir
from pprint import pprint
from python_terraform import *
json_data=open('./terraform.json')
data = json.load(json_data)
json_data.close()
for i in range (0, len (data['modules'])):
print data['modules']['path']['outputs'][1]
And getting following error:
File "./1.py", line 17, in <module>
for i in range (0, len (data['modules']['path']['outputs'])):
TypeError: list indices must be integers, not str
also tried:
for dat in data:
print dat['outputs']
We can see from your JSON that modules is a list, which maps to an array with numeric indices, not a dictionary. (Though, there seems to be only one item in the list.)
So you need to iterate over it with i.
See what you are actually receiving with something like:
for i in range (0, len (data['modules'])):
pprint(data['modules'][i]['outputs']['id']['value'])
Which outputs:
$ python 1.py
[u'34.244.138.72', u'34.249.95.222']

Modifying elasticsearch score based on nested field value

I want to modify scoring in ElasticSearch (v2+) based on the weight of a field in a nested object within an array.
For instance, using this data:
PUT index/test/0
{
"name": "red bell pepper",
"words": [
{"text": "pepper", "weight": 20},
{"text": "bell","weight": 10},
{"text": "red","weight": 5}
]
}
PUT index/test/1
{
"name": "hot red pepper",
"words": [
{"text": "pepper", "weight": 15},
{"text": "hot","weight": 11},
{"text": "red","weight": 5}
]
}
I want a query like {"words.text": "red pepper"} which would rank "red bell pepper" above "hot red pepper".
The way I am thinking about this problem is "first match the 'text' field, then modify scoring based on the 'weight' field". Unfortunately I don't know how to achieve this, if it's even possible, or if I have the right approach for something like this.
If proposing alternative approach, please try and keep a generalized idea where there are tons of different similar cases (eg: simply modifying the "red bell pepper" document score to be higher isn't really a suitable alternative).
The approach you have in mind is feasible. It can be achieved via function score in a nested query .
An example implementation is shown below :
PUT test
PUT test/test/_mapping
{
"properties": {
"name": {
"type": "string"
},
"words": {
"type": "nested",
"properties": {
"text": {
"type": "string"
},
"weight": {
"type": "long"
}
}
}
}
}
PUT test/test/0
{
"name": "red bell pepper",
"words": [
{"text": "pepper", "weight": 20},
{"text": "bell","weight": 10},
{"text": "red","weight": 5}
]
}
PUT test/test/1
{
"name": "hot red pepper",
"words": [
{"text": "pepper", "weight": 15},
{"text": "hot","weight": 11},
{"text": "red","weight": 5}
]
}
post test/_search
{
"query": {
"bool": {
"disable_coord": true,
"must": [
{
"match": {
"name": "red pepper"
}
}
],
"should": [
{
"nested": {
"path": "words",
"query": {
"function_score": {
"functions": [
{
"field_value_factor": {
"field" : "words.weight",
"missing": 0
}
}
],
"query": {
"match": {
"words.text": "red pepper"
}
},
"score_mode": "sum",
"boost_mode": "replace"
}
},
"score_mode": "total"
}
}
]
}
}
}
Result :
"hits": [
{
"_index": "test",
"_type": "test",
"_id": "0",
"_score": 26.030865,
"_source": {
"name": "red bell pepper",
"words": [
{
"text": "pepper",
"weight": 20
},
{
"text": "bell",
"weight": 10
},
{
"text": "red",
"weight": 5
}
]
}
},
{
"_index": "test",
"_type": "test",
"_id": "1",
"_score": 21.030865,
"_source": {
"name": "hot red pepper",
"words": [
{
"text": "pepper",
"weight": 15
},
{
"text": "hot",
"weight": 11
},
{
"text": "red",
"weight": 5
}
]
}
}
]
}
The query in a nutshell would score a document that satisfies the must clause as follows : sum up the weights of the matched nested documents with the score of the must clause.

Resources