{"_id":"@ckyrouac/json-schema-to-es-mapping","_rev":"2-669456285174b174a751cbadb8d1cc2a","name":"@ckyrouac/json-schema-to-es-mapping","dist-tags":{"latest":"0.3.7"},"versions":{"0.3.6":{"name":"@ckyrouac/json-schema-to-es-mapping","version":"0.3.6","main":"src/index.js","description":"Generate Elastic Search mappings from JSON Schema","license":"MIT","author":{"name":"Kristian Mandrup","email":"kmandrup@gmail.com"},"homepage":"https://github.com/kristianmandrup/json-schema-to-es-mapping#readme","repository":{"type":"git","url":"git+https://github.com/kristianmandrup/json-schema-to-es-mapping.git"},"bugs":{"url":"https://github.com/kristianmandrup/json-schema-to-es-mapping/issues","email":"kmandrup@gmail.com"},"devDependencies":{"jest":"^23.0.0"},"keywords":["elastic","search","elasticsearch","elastic-search","json","json-schema","schema","convert","build","builder","generator"],"scripts":{"test":"jest"},"dependencies":{"dot-prop":"^5.0.0","inflection":"^1.12.0"},"publishConfig":{"access":"public"},"gitHead":"d08fb7431c79edab3004adb4aab49c1ad0e9333b","_id":"@ckyrouac/json-schema-to-es-mapping@0.3.6","_nodeVersion":"16.13.0","_npmVersion":"8.1.0","dist":{"integrity":"sha512-KNEvnU+Ip0XxyjdSgGlK2DMI1y3YiZiCWegpSk3XDRCtfKzA6Wmc8ZW2wKBk+CRhsiFSfCiR5qxvx/jMuWLe0Q==","shasum":"db5463b2e7c19228354b333bb34827f8a3e44629","tarball":"https://registry.npmjs.org/@ckyrouac/json-schema-to-es-mapping/-/json-schema-to-es-mapping-0.3.6.tgz","fileCount":38,"unpackedSize":62070,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJh9+UtCRA9TVsSAnZWagAA7TAQAIJ+3vW0kZTnTWiDSNab\nvt1oND+JYBF6JnK/kjw6E6W/hb3+BoAdoWE8fEQpf5SxoZCCQp1gZR92ZbgY\nDWaQyMjfzxt+AO/Wb+zZ0BKHpSZ2OrJxoz+pOvP2ols+f4ptnEMYrmo+YXqg\n63KoW9xU8r0xZdJiuyIg+IKy3YPMP9mOodRQyXRD6Y9TOWvaDGT1dq7xs6tv\nsTso6lvCVEwghRjdoF9HfPirG+doZhF4ePljPdz2YftM5n++ImJZRfslgN5v\nhHvFZ+0cCqRzVLwDtGGcEJueU7cj2fQm0ri0RW2hEazOcLDSPFNTVkIxi43B\nnis4lj3DsqhWsKp4VRQgb8sw56IAYo5nZUXTOe/RL3XRmLPwIhPTvVoqOij3\nTmargZNZzDX9iZTxUs5r9mjNMS+dv5kxAGuCDi9XZlENl/fxMal8fpb1K/yC\no8QQIVvQEGBDRNvFnBmclytHPxoSGielyKAIbsVl1qliqhq3cz+TDkOGlqYe\nIGF4JNj1esWCW05rA69alz0auWumQ4+yTbDG7pRxtm+i06lCuxSqN5mXhHrv\n8tFhha6rtnID1wQBjeQ9Q5e+m3RXU2EGmmqYzB8ZyStQqH0tZKdEVD7Upj9I\nObMwlwgINZ/EfbQiXNlUz0LvKAItKrkT9fC1Mqk3NhHbJYgPRGbiHOYMMqKo\nmlM4\r\n=lNUe\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDuX8Cvm1YzZngpFbcr+BjBZe6wkzWqBIniGOd6KvzokgIhAPirBEpuja/L5rCLgtFAaKSmy8KTYUP7AGhu9ZZpdlio"}]},"_npmUser":{"name":"ckyrouac","email":"ckyrouac@redhat.com"},"directories":{},"maintainers":[{"name":"ckyrouac","email":"ckyrouac@redhat.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/json-schema-to-es-mapping_0.3.6_1643636013562_0.11004208725389142"},"_hasShrinkwrap":false},"0.3.7":{"name":"@ckyrouac/json-schema-to-es-mapping","version":"0.3.7","main":"src/index.js","description":"Generate Elastic Search mappings from JSON Schema","license":"MIT","author":{"name":"Kristian Mandrup","email":"kmandrup@gmail.com"},"homepage":"https://github.com/RedHatInsights/json-schema-to-es-mapping#readme","repository":{"type":"git","url":"git+https://github.com/RedHatInsights/json-schema-to-es-mapping.git"},"bugs":{"url":"https://github.com/RedHatInsights/json-schema-to-es-mapping/issues"},"devDependencies":{"jest":"^23.0.0"},"keywords":["elastic","search","elasticsearch","elastic-search","json","json-schema","schema","convert","build","builder","generator"],"scripts":{"test":"jest"},"dependencies":{"dot-prop":"^5.0.0","inflection":"^1.12.0"},"publishConfig":{"access":"public"},"gitHead":"d08fb7431c79edab3004adb4aab49c1ad0e9333b","_id":"@ckyrouac/json-schema-to-es-mapping@0.3.7","_nodeVersion":"16.13.0","_npmVersion":"8.1.0","dist":{"integrity":"sha512-ThUwRfYTKP9a5dNp0WNJGq+X5fQqsFnebIZmzoxnvQ6Bjm5dSMFO3P+e200U57Dq1ED7+Rp/1Zn6CzMB5/CGMg==","shasum":"1f94cf411a0af842e1e63856bf514aa7c9d82f19","tarball":"https://registry.npmjs.org/@ckyrouac/json-schema-to-es-mapping/-/json-schema-to-es-mapping-0.3.7.tgz","fileCount":38,"unpackedSize":62032,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJh9+XKCRA9TVsSAnZWagAAqjkP/0SRY10kzxTx7iLQhwBm\nJMLa8ZLBohpyWuArOmdEq7HJSjuX/iNR1ItLio8E7kWrbyWo8XaPMjpty5Ww\noTgaA4WQXJd47NthVxnjRVuh1LBfbnocO5Z04/K9jgoXilkE0t2kJ3fxUeNT\ntukS+meB7Z6Hn0la2Xo6cKo24y3fZj2HhM9q1og9MZJ9XVIDURhBir3/G9Ud\nFDJUvbfjbOSQ+8QpbRU/0AqCyYh6ETgP3vBUr1rtnG3ANkDryDVtZH3Y+Z3P\nSjCETuBsno4sVyyMH3sj91msRtn6WrungGfR2a9EkLFACmiY0mIC6iFi+S+w\nNBx+JqLO4GIIuAFmHzNsSMFIp+BHWYm7hF6whmERsFi2wQuZ+7ioM518281X\nh0s48bH64OFqQoei9Rsi4m1b4ZvqJeuXG7EG1mNw4lnm/4pIox4fq8xTqi4F\n/1Dz6S/da+LbySDnK1srp6vVweI/E4G89pQO7EBW3zZDkzkcPgEEqG0dG20k\n/Pj5RAfsaVLZOOzu1tVbQCvIF6EGlfqK7NIoisww/4gjsfTa2KDFBHgDg5Zr\nrBiHOMpZnl0wl2BlZlD5SRT1SzGxBLg1yoi4M1zirOOu5C+M7U76EdyAK3g5\nalBMiGJZ4Bs4BeLwyMhWymUg/4hWhalGGx86Jgc3r2HfFKLgj2GqrKXT2WRs\n/4mc\r\n=D4Pj\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCfRiUysZ2qDjmSlSK7mKJ3ma6pUIb+G4KNx0MkjaiZ9AIhAJHA2t2ZGPjO0kLPWrqBZDs6Vijqk8/rC7e3PMNZNw2d"}]},"_npmUser":{"name":"ckyrouac","email":"ckyrouac@redhat.com"},"directories":{},"maintainers":[{"name":"ckyrouac","email":"ckyrouac@redhat.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/json-schema-to-es-mapping_0.3.7_1643636169836_0.5901728543645866"},"_hasShrinkwrap":false}},"time":{"created":"2022-01-31T13:33:33.468Z","0.3.6":"2022-01-31T13:33:33.683Z","modified":"2022-04-04T23:11:42.762Z","0.3.7":"2022-01-31T13:36:10.022Z"},"maintainers":[{"name":"ckyrouac","email":"ckyrouac@redhat.com"}],"description":"Generate Elastic Search mappings from JSON Schema","homepage":"https://github.com/RedHatInsights/json-schema-to-es-mapping#readme","keywords":["elastic","search","elasticsearch","elastic-search","json","json-schema","schema","convert","build","builder","generator"],"repository":{"type":"git","url":"git+https://github.com/RedHatInsights/json-schema-to-es-mapping.git"},"author":{"name":"Kristian Mandrup","email":"kmandrup@gmail.com"},"bugs":{"url":"https://github.com/RedHatInsights/json-schema-to-es-mapping/issues"},"license":"MIT","readme":"# JSON Schema to ElasticSearch mappings\n\nConvert JSON schema to [ElasticSearch mappings](https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping.html)\n\nA mapping type has:\n\n_Meta-fields_\n\nMeta-fields are used to customize how a document’s metadata associated is treated. Examples of meta-fields include the document’s `_index`, `_type`, `_id`, and `_source` fields.\n\n_Fields or properties_\n\nA mapping `type` contains a list of fields or properties pertinent to the document.\n\n_Field datatypes_\n\nEach field has a data `type` which can be:\n\n- a simple type like `text`, `keyword`, `date`, `long`, `double`, `boolean` or `ip`\n- a type which supports the hierarchical nature of JSON such as `object` or `nested`\n- a specialised type like `geo_point`, `geo_shape`, or `completion`\n\nIt is often useful to index the same field in different ways for different purposes. For instance, a `string` field could be indexed as a `text` field for full-text search, and as a `keyword` field for sorting or aggregations. Alternatively, you could index a string field with the `standard` analyzer, the `english` analyzer, and the `french` analyzer.\n\nThis is the purpose of multi-fields. Most datatypes support multi-fields via the `fields` parameter.\n\n## Quick start\n\n- npm: `npm install json-schema-to-es-mapping -S`\n- yarn: `yarn add json-schema-to-es-mapping`\n\nThe easiest way to get started is to use `buildMappingsFor` to create a mappings object for a named index given a JSON schema.\n\n```js\nconst mappings = buildMappingsFor(\"people\", schema);\n```\n\nExample:\n\n```js\nconst schema = {\n  $schema: \"http://json-schema.org/draft-07/schema#\",\n  $id: \"http://example.com/person.schema.json\",\n  title: \"Person\",\n  description: \"A person\",\n  type: \"object\",\n  properties: {\n    name: {\n      description: \"Name of the person\",\n      type: \"string\"\n    },\n    age: {\n      description: \"Age of person\",\n      type: \"number\"\n    }\n  },\n  required: [\"name\"]\n};\n\nconst { buildMappingsFor } = require(\"json-schema-to-es-mapping\");\nconst mappings = buildMappingsFor(\"people\", schema);\nconsole.log({ mappings });\n```\n\nThis will by default give the following mappings result:\n\n```json\n{\n  \"mappings\": {\n    \"people\": {\n      \"properties\": {\n        \"name\": {\n          \"type\": \"keyword\"\n        },\n        \"age\": {\n          \"type\": \"integer\"\n        }\n      }\n    }\n  }\n}\n```\n\nThe function `buildMappingsFor` uses the `build` function to return the properties map and simply wraps them with a `mappings` object for the named index.\n\n## Supported mappings\n\nCurrently all Elastic Search core data types are supported (except for `binary`).\n\n- string\n- numeric\n- boolean\n- date\n- object\n- ranges (numeric, date) (soon)\n- geo_point (soon)\n- ip (soon)\n\nNote: The most feature complete version can currently be found in the [to-ts](https://github.com/kristianmandrup/json-schema-to-es-mapping/commits/to-ts) branch. This branch is almost complete. It has unit test coverage of most of the functionality, includes initial support for complex schema types (such as `anyOf` a list of types) and the code has been converted to TypeScript. \n\nPlease help with the finishing touches so it can be released if you want or need these extra mappings and other features.\n\n### Numeric\n\nYou can assist the numeric type mapper by supplying a `numType` for the field entry, such as `numType: \"double\"`\n\nSee ES [number](https://www.elastic.co/guide/en/elasticsearch/reference/current/number.html#number) reference for list of valid `numType`s (except for `scaled_float`)\n\n### Ranges\n\n- Numeric\n- Date\n\n#### Numeric ranges\n\nTo make a numeric field entry be mapped to an ES numeric range:\n\n- Set `range: true`\n- Set a minimum range value, either `minimum` or `exlusiveMinimum`\n- Set a maximum range value, either `maximum` or `exlusiveMaximum`\n\nIf you leave out the `range: true` it will be resolved as a number, using the min and max values and the `multipleOf` (precision). These properties will in combination be used to determine the exact numeric type (`byte`, `short`, ... `double`) to be used in the Elastic Search numeric type mapping.\n\n#### Date ranges\n\nTo make an entry detect as a date range, the same applies as for a number range but the entry must also resolve to a date type (see `types/util.js` function `isDate(obj)` for details)\n\n## Recent feature additions\n\nNow also resolves:\n\n- Array items that are themselves object types\n- References to object definitions (ie. `$ref`)\n- [Parent-child mapping](https://www.elastic.co/guide/en/elasticsearch/guide/current/parent-child-mapping.html)\n\n## Limitations and coming features\n\nSupport for Geo location mapping will likely be included in the near future. \n\nPlease Let me know any other features you'd like to include for a more feature complete library!\n\nInitial work to support these features have been started in the [dev](https://github.com/kristianmandrup/json-schema-to-es-mapping/tree/dev) branch and should land soon (0.4.0).\n\n## Fine grained control\n\nFor more fine-grained control, use the `build` function directly.\n\n```js\nconst { build } = require(\"json-schema-to-es-mapping\");\nconst { properties, results } = build(schema);\nconsole.log({ properties, results });\n```\n\nWill output the following Elastic Search Mapping schema:\n\n```json\n{\n  \"name\": {\n    \"type\": \"text\"\n  },\n  \"age\": {\n    \"type\": \"float\"\n  }\n}\n```\n\nThe `results` will in this (simple) case give the same results as the `mappings`:\n\n```js\n{\n  name: { type: \"keyword\" },\n  age: { type: \"float\" }\n}\n```\n\n## Event driven approach\n\nYou can use the Event driven approach with the `onResult` and other calback handlers, to generate a more context specific mapping for Elastic Search context, given your requirements.\n\n```js\nconst received = [];\nconst onResult = result => {\n  console.log(\"received\", result);\n  received.push(result);\n};\n\n// potentially use to call resolve callback of Promise\nconst onComplete = fullResult => {\n  console.log(\"ES mapping done :)\", {\n    fullResult, // 'internal\" results\n    received // list built by onResult\n  });\n};\n\n// potentially use to call reject callback of Promise\nconst onError = errMsg => {\n  console.error(\"ES mapping error\", errMsg);\n  throw errMsg;\n};\n\n// potentially use to call reject callback of Promise\nconst onThrow = err => throw err;\nconst config = { onResult, onComplete, onError, onThrow };\n```\n\nThe `onResult` handler will populate the `received` array with the following:\n\n```js\n[\n  { parentName: \"Person\", key: \"name\", resultKey: \"name\", type: \"text\" },\n  {\n    parentName: \"Person\",\n    key: \"age\",\n    resultKey: \"age\",\n    type: \"float\"\n  }\n];\n```\n\nYou will also get notified on:\n\n- successful completion of JSON schema mapping via `onComplete` callback\n- aborted due to processing error via `onError` callback\n- aborted due to throwing exception via `onThrow` callback\n\nThe Event driven approach is entirely optional, but can be used for a more \"stream like\" approach. This approach works well with async promises (ie. `reject` and `resolve` callbacks).\n\nOn each result received you can then issue a command to the Elastic Search server (f.ex via the REST interface) to add a new mapping that reflects the result received.\n\n[Put mapping](https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-put-mapping.html)\n\n```bash\nPUT person/_mapping/_doc\n{\n  \"properties\": {\n    \"age\": {\n      \"type\": \"float\"\n    }\n  }\n}\n```\n\nAlternatively only submit the ES index mappings after `onComplete` is triggered, to make sure the full JSON schema could be processed, so that you don't end up with partial schema mappings.\n\n## Nested schemas\n\nFor a nested schema of the form:\n\n```js\n{\n  $schema: \"http://json-schema.org/draft-07/schema#\",\n  $id: \"http://example.com/person.schema.json\",\n  title: \"Person\",\n  description: \"A person\",\n  type: \"object\",\n  properties: {\n    name: {\n      description: \"Name of the person\",\n      type: \"string\"\n    },\n    dog: {\n      type: \"object\",\n      typeName: \"Animal\",\n      properties: {\n        name: {\n          description: \"Name of the dog\",\n          type: \"string\",\n          required: true\n        },\n        age: {\n          description: \"Age of dog\",\n          type: \"number\"\n        }\n      }\n    }\n  },\n  required: [\"name\"]\n};\n```\n\n`buildMappingsFor` will in this case generate an Elastic Search mapping as follows:\n\n```js\nmappings: {\n  people: {\n    properties: {\n      name: {\n        type: \"keyword\"\n      },\n      dog: {\n        properties: {\n          name: {\n            type: \"keyword\"\n          },\n          age: {\n            type: \"float\"\n          }\n        }\n      }\n    }\n  }\n}\n```\n\nNote that the `dog` object results in a nested mapping (see ElasticSearch resources below)\n\nThe `results` will in this case give:\n\n```js\n{\n  name: { type: 'keyword' },\n  dog_name: { type: 'keyword' },\n  dog_age: { type: 'float' },\n  dog: {\n    name: { type: 'keyword' },\n    age: { type: 'float' }\n  }\n}\n```\n\nNotice how the dog properties are provided both in flat and nested form. Depending on your requirements, you might want to store the Elastic Search data in a more flat form than in your general application domain model.\n\n### Customizing the result\n\nYou can pass a custom function `shouldSetResult(converter)` which controls under which converter conditions the result should be set. You can also pass:\n\n- a custom name separator `nameSeparator`\n- a `resultKey(converter)` function, to customize how result keys (names) are generated\n- a `nestedKey(converter)` function, to customize how nested result keys (names) are generated\n\nExample:\n\n```js\nconst config = {\n  shouldSetResult: converter => {\n    return converter.type !== \"object\";\n  },\n  nameSeparator: \"__\" // example: dog__age\n};\n```\n\nThis configuration will result in results discarding the nested form, thus only retaining flattened field mappings.\n\n```js\n{\n  name: { type: 'keyword' },\n  dog__name: { type: 'keyword' },\n  dog__age: { type: 'float' },\n}\n```\n\nIf you add an `onResult` handler to receive results, it will look as follows:\n\n```js\nresults:\n  [\n    {\n      parentName: 'Person',\n      key: 'name',\n      resultKey: 'name',\n      type: 'keyword'\n    },\n    {\n      parentName: 'dog',\n      key: 'name',\n      resultKey: 'dog__name',\n      type: 'keyword'\n    },\n    { parentName: 'dog',\n      key: 'age',\n      resultKey: 'dog__age',\n      type: 'float'\n    },\n    { parentName: 'Person',\n      typeName: 'Animal',\n      key: 'dog',\n      resultKey: 'dog',\n      properties: {\n        name: { type: 'keyword' },\n        age: { type: 'float' }\n      }\n    }\n  ]\n}\n```\n\nNote the `typeName` in the result for the `dog` fields (more on this later)\n\n## Default configuration\n\nThe default configuration is as follows.\n\n```js\n{\n  _meta_: {\n    types: {\n      string: \"keyword\",\n      number: \"float\",\n      object: \"object\",\n      array: \"nested\",\n      boolean: \"boolean\",\n      date: \"date\"\n    }\n  },\n  fields: {\n    name: {\n      type: \"keyword\"\n    },\n    content: {\n      type: \"text\"\n    },\n    text: {\n      type: \"text\"\n    },\n    title: {\n      type: \"text\"\n    },\n    caption: {\n      type: \"text\"\n    },\n    label: {\n      type: \"text\"\n    },\n    tag: {\n      type: \"keyword\",\n      index:    \"not_analyzed\"\n    }\n  }\n}\n```\n\nNote that some or all of these might benefit from being defined as multi fields, that are indexed and analyzed both as `text` and `keyword`.\n\nYou can pass in a custom configuration object (last argument) to override or extend it ;)\n\nNote that for convenience, we pass in some typical field mappings based on names. Please customize this further to your needs.\n\n## Customization\n\n- Type mappers\n- Rules\n\n### Type mappers\n\nYou can pass in custom Type mapper factories if you want to override how specific types are mapped.\n\nInternally this is managed in the `SchemaEntry` constructor in `entry.js`:\n\n```js\nthis.defaults = {\n  types: {\n    string: toString,\n    number: toNumber,\n    boolean: toBoolean,\n    array: toArray,\n    object: toObject,\n    date: toDate,\n    dateRange: toDateRange,\n    numericRange: toNumericRange\n  },\n  typeOrder: [\n    \"string\",\n    \"dateRange\",\n    \"numericRange\",\n    \"number\",\n    \"boolean\",\n    \"array\",\n    \"object\",\n    \"date\"\n  ]\n};\n\nthis.types = {\n  ...this.defaults.types,\n  ...(config.types || {})\n};\nthis.typeOrder = config.typeOrder || this.defaults.typeOrder;\n```\n\nTo override, simply pass in a custom `types` object and/or a custom `typeOrder` array of the precedence order they should be resolved in.\n\n#### Custom Type mapper example (object)\n\nCreate a `toObject` file loally in your project that contains your overrides\n\n```js\nconst { types } = require(\"json-schema-to-es-mapping\");\nconst { MappingObject, toObject, util } = types;\n\nclass MyMappingObject extends MappingObject {\n  // ...override\n\n  createMappingResult() {\n    return this.hasProperties\n      ? this.buildObjectValueMapping()\n      : this.defaultObjectValueMapping;\n  }\n\n  buildObjectValueMapping() {\n    const { buildProperties } = this.config;\n    return buildProperties(this.objectValue, this.mappingConfig);\n  }\n}\n\nmodule.exports = function toObject(obj) {\n  return util.isObject(obj) && new MyMappingObject(obj).convert();\n};\n```\n\nImport the `toObject` function and pass it in the `types` object of the `config` object passed to the `build` function.\n\n```js\n// custom implementation\nconst toObject = require(\"./toObject\");\n\nconst myConfig = {\n  types: {\n    toObject\n  }\n};\n\n// will now use the custom toObject for mapping JSON schema object to ES object\nbuild(schema, myConfig);\n```\n\nDepending on your requirements, you can post-process the generated mapping to better suit your specific needs and strategies for handling nested/complex data relationships.\n\n## Elastic search types\n\n- [Elasticsearch: mapping types](https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-types.html)\n\nCore:\n\n- String (`text`, `keyword`)\n- Numeric (`long`, `integer`, `short`, `byte`, `double`, `float`, `half_float`, `scaled_float`)\n- Date (`date`)\n- Boolean (`boolean`)\n- Binary (`binary`)\n- Range (`integer_range`, `float_range`, `long_range`, `double_range`, `date_range`)\n\n## Type mappings\n\nThe default type mappings are as follows:\n\n- `boolean` -> `boolean`\n- `object` -> `object`\n- `array` -> `nested`\n- `string` -> `keyword`\n- `number` -> `integer`\n- `date` -> `date`\n\nFor `array` it will use `type` of first [array item](https://cswr.github.io/JsonSchema/spec/arrays/) if [basic type](https://cswr.github.io/JsonSchema/spec/basic_types/) and the type for all array items are the same.\n\n```js\n{\n  \"type\": \"array\",\n  \"items\":{\n    \"type\": \"integer\"\n  }\n}\n```\n\nIf array item types are note \"uniform\" it will throw an error.\n\nFor the following array JSON schema entry the mapper will currently set the mapping type to `string` (by default). Please use the customization options outlined to define a more appropriate mapping strategy if needed.\n\n```js\n{\n \"type\": \"array\",\n \"items\" : [{\n    \"type\": \"string\"\n    // ...\n  },\n  {\n    \"type\": \"string\"\n    // ...\n  },\n ]\n}\n```\n\nYou can override the default type mappings by passing a `types` entry with type mappings in the `_meta_` entry of `config`\n\n```js\nconst config = {\n  _meta_: {\n    types: {\n      number: \"long\", // use \"integer\" for numbers\n      string: \"text\" // use \"text\" for strings\n    }\n  }\n};\n```\n\n### Rules\n\nYou can pass an extra configuration object with specific rules for ES mapping properties that will be merged into the resulting mapping.\n\n```js\nconst config = {\n  _meta_: {\n    types: {\n      number: \"long\", // use \"integer\" for numbers\n      string: \"text\" // use \"text\" for strings\n    }\n  },\n  fields: {\n    created: {\n      // add extra indexing field meta data for Elastic search\n      format: \"strict_date_optional_time||epoch_millis\"\n      // ...\n    },\n    firstName: {\n      type: \"keyword\" // make sure firstName will be a keyword field (exact match) in ES mapping\n    }\n  }\n};\n\nconst { build } = require(\"json-schema-to-es-mapping\");\nconst mapping = build(schema, config);\n```\n\nAlso note that you can pass in many of the functions used internally, so that the internal mechanics themselves can easily be customized as needed or used as building blocks.\n\n### Elastic Search nested objects and data\n\n- [Elasticsearch: Nested datatype](https://www.elastic.co/guide/en/elasticsearch/reference/current/nested.html)\n- [Elasticsearch: Nested Objects](https://www.elastic.co/guide/en/elasticsearch/guide/current/nested-objects.html)\n- [Elasticsearch data schema for nested objects](https://stackoverflow.com/questions/43488166/elasticsearch-data-schema-for-nested-objects)\n- [Elasticsearch : Advanced search and nested objects](http://obtao.com/blog/2014/04/elasticsearch-advanced-search-and-nested-objects/)\n\n## Advanced customization\n\nTo override the default mappings for certain fields, you can pass in a fields mapping entry in the `config` object as follows:\n\n```js\nconst config = {\n  fields: {\n    timestamp: {\n      type: \"date\",\n      format: \"dateOptionalTime\"\n    }\n    // ... more custom field mappings\n  }\n};\n```\n\nFor a more scalable customization, pass an `entryFor` function which returns custom mappings\ndepending on the entry being processed.\n\n- `key`\n- `resultKey` (ie. potentially nested key name)\n- `parentName` name of parent entry if nested property\n- `schemaValue` (entry from JSON schema being mapped)\n\nYou could f.ex use this to provide custom mappings for specific types of date fields.\n\n```js\nconst config = {\n  entryFor: ({ key }) => {\n    if (key === \"date\" || key === \"timestamp\") {\n      return {\n        type: \"date\",\n        format: \"dateOptionalTime\"\n      };\n    }\n  }\n};\n```\n\n### resolve type maps\n\nYou can use [resolve-type-maps](https://github.com/kristianmandrup/resolve-type-maps) to define mappings to be used across your application in various schema-like contexts:\n\n- GraphQL schema\n- Data storage (tables, colletions etc)\n- Validation\n- Forms\n- Data Display\n- Indexing (including Elastic Search)\n- Mocks and fake data\n\n```js\nconst fieldMap = {\n  name: {\n    matches: ['title', 'caption', 'label'],\n    elastic: {\n      type: 'string',\n    }\n  }\n  tag: {\n    matches: ['tags'],\n    elastic: {\n      type: 'keyword',\n    }\n\n  },\n  text: {\n    matches: ['description', 'content'],\n    elastic: {\n      type: 'text',\n    }\n  },\n  date: {\n    matches: ['date', 'timestamp'],\n    elastic: {\n      type: 'text',\n      format: 'dateOptionalTime'\n    }\n  }\n}\n\nconst typeMap = {\n  Person: {\n    matches: ['User'],\n    fields: {\n      dog: {\n        // ...\n        elastic: {\n          type: 'nested',\n          // ...\n        }\n      },\n      // ...\n    }\n  }\n}\n```\n\nThen pass an `entryFor` function in the config object to resolve the entry to be used for the ES mapping entry.\n\n```js\nimport { createTypeMapResolver } from \"resolve-type-maps\";\n\nconst map = {\n  typeMap,\n  fieldMap\n};\n\nconst resolverConfig = {};\nconst functions = {\n  resolveResult: (obj) => obj.elastic;\n}\n\nconst resolver = createTypeMapResolver(\n  { map, functions },\n  resolverConfig\n);\n\nconst config = {\n  entryFor: ({ parentName, typeName }) => {\n    // ensure capitalized and camelized name\n    const type = classify(typeName || parentName);\n    const name = converter.key;\n    return resolver.resolve({ type, name });\n  }\n};\n```\n\nNote that for `typeName` to be set, either set a `className` or `typeName` property on the object entry in the JSON schema (see `dog` example above) or alternatively provide a lookup function `typeNameFor(name)` on the config object passed in.\n\nFor inner workings, see [TypeMapResolver.ts](https://github.com/kristianmandrup/resolve-type-maps/blob/master/src/lib/TypeMapResolver.ts)\n\nThe above configuration should look up the elastic mapping entry to use, based on the type/field combination in the `typeMap` first and then fall back to the field name only in the `fieldMap` if not found. On a match, it will resolve by returning entry named `elastic` in the object matching.\n\n```js\n{\n  Person: {\n    matches: [/User/],\n    fields: {\n      dog: {\n        // ...\n        elastic: {\n          type: 'nested',\n          // ...\n        }\n      },\n    }\n  }\n}\n```\n\nIt should match a schema (or nested schema entry) named `Person` or `User` on the `typeMap` entry `Person`. For the nested `dog` entry it should then match on the entry `dog` under `fields` and return the entry for elastic, ie:\n\n```js\n{\n  type: \"nested\";\n}\n```\n\nIf no match is made in the `typeMap`, it will follow a similar strategy by lookup a match in the `fieldMap` (as per the `maps` entry passed in the `config` object when creating the `resolver`), matching only on the field name.\n\n## ElasticSearch mapping resources\n\n- [mapping](https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping.html)\n- [removal of types](https://www.elastic.co/guide/en/elasticsearch/reference/current/removal-of-types.html)\n- [nested](https://www.elastic.co/guide/en/elasticsearch/reference/current/nested.html)\n\n## Testing\n\nUses [jest](jestjs.io/) for unit testing.\n\nCurrently not well tested. Please help add more test coverage :)\n\n## TODO\n\n### 1.0.0\n\n- Convert project to TypeScript\n- Add unit tests for ~80% test coverage\n- Improve mappings for:\n  - Date range\n\n## Author\n\n2019 Kristian Mandrup (CTO@Tecla5)\n\n## License\n\nMIT\n","readmeFilename":"Readme.md"}