{"id":514,"date":"2018-02-14T20:30:24","date_gmt":"2018-02-14T12:30:24","guid":{"rendered":"https:\/\/vinta.ws\/code\/?p=514"},"modified":"2026-03-17T01:16:31","modified_gmt":"2026-03-16T17:16:31","slug":"mongodb-cookbook-indexes","status":"publish","type":"post","link":"https:\/\/vinta.ws\/code\/mongodb-cookbook-indexes.html","title":{"rendered":"MongoDB cookbook: Indexes"},"content":{"rendered":"<p>Indexes are crucial for the efficient execution of queries and aggregations in MongoDB. Without indexes, MongoDB must perform a collection scan, i.e., scan every document in a collection.<\/p>\n<p>If a write operation modifies an indexed field, MongoDB updates all indexes that have the modified field as a key. So, be careful while choosing indexes.<\/p>\n<h2>Types Of Indexes<\/h2>\n<p>ref:<br \/>\n<a href=\"https:\/\/docs.mongodb.com\/manual\/indexes\/\">https:\/\/docs.mongodb.com\/manual\/indexes\/<\/a><br \/>\n<a href=\"https:\/\/docs.mongodb.com\/manual\/applications\/indexes\/\">https:\/\/docs.mongodb.com\/manual\/applications\/indexes\/<\/a><\/p>\n<h3>Single Field Index<\/h3>\n<p>For a single field index and sort operations, the sort order (i.e. ascending or descending) of the index key doesn't matter. With index intersection, single field indexes could be powerful.<\/p>\n<p>ref:<br \/>\n<a href=\"https:\/\/docs.mongodb.com\/manual\/core\/index-single\/\">https:\/\/docs.mongodb.com\/manual\/core\/index-single\/<\/a><\/p>\n<h3>Compound Index<\/h3>\n<p>The order of the fields listed in a compound index is very important.<\/p>\n<p>ref:<br \/>\n<a href=\"https:\/\/docs.mongodb.com\/manual\/core\/index-compound\/\">https:\/\/docs.mongodb.com\/manual\/core\/index-compound\/<\/a><br \/>\n<a href=\"https:\/\/docs.mongodb.com\/manual\/tutorial\/create-indexes-to-support-queries\/\">https:\/\/docs.mongodb.com\/manual\/tutorial\/create-indexes-to-support-queries\/<\/a><\/p>\n<h3>TTL Index<\/h3>\n<p>When the TTL thread is active, a background thread in mongod reads the values in the index and removes expired documents from the collection. You will see delete operations in the output of <code>db.currentOp()<\/code>.<\/p>\n<p>TTL indexes are single-field indexes. Compound indexes do not support TTL and ignore the <code>expireAfterSeconds<\/code> option.<\/p>\n<pre class=\"line-numbers\"><code class=\"language-py\">import datetime\n\nclass JournalEntry(db.Document):\n    users = db.ListField(db.ReferenceField('User'))\n    event = db.StringField()\n    context = db.DynamicField()\n    timestamp = db.DateTimeField(default=datetime.datetime.utcnow)\n\n    meta = {\n        'index_background': True,\n        'indexes': [\n            {\n                'fields': ['timestamp'],\n                'cls': False,\n                'expireAfterSeconds': int(datetime.timedelta(days=90).total_seconds()),\n            },\n        ],\n    }<\/code><\/pre>\n<p>ref:<br \/>\n<a href=\"https:\/\/docs.mongodb.com\/manual\/core\/index-ttl\/\">https:\/\/docs.mongodb.com\/manual\/core\/index-ttl\/<\/a><\/p>\n<h3>Index Intersection<\/h3>\n<p>MongoDB can use multiple single field indexes to fulfill queries.<\/p>\n<pre class=\"line-numbers\"><code class=\"language-js\">db.orders.createIndex({tags: 1});\ndb.orders.createIndex({key: { created_at: -1 }, background: true});\n\ndb.orders.find({item: 'abc123', qty: {$gt: 15}});<\/code><\/pre>\n<p>ref:<br \/>\n<a href=\"https:\/\/docs.mongodb.com\/manual\/core\/index-intersection\/\">https:\/\/docs.mongodb.com\/manual\/core\/index-intersection\/<\/a><\/p>\n<h3>Covered Queries<\/h3>\n<p>ref:<br \/>\n<a href=\"https:\/\/docs.mongodb.com\/manual\/core\/query-optimization\/#read-operations-covered-query\">https:\/\/docs.mongodb.com\/manual\/core\/query-optimization\/#read-operations-covered-query<\/a><\/p>\n<h2>Index Limits<\/h2>\n<p>The size of an  index entry for an indexed field must be less than 1024 bytes. For instance, an arbitrary URL field can easily exceed 1024 bytes. <\/p>\n<p>MongoDB will not insert into an indexed collection any document with an indexed field whose corresponding index entry would exceed the index key limit, and instead will return an error. Updates to the indexed field will error if the updated value causes the index entry to exceed the index key limit.<\/p>\n<p>ref:<br \/>\n<a href=\"https:\/\/docs.mongodb.com\/manual\/reference\/limits\/#indexes\">https:\/\/docs.mongodb.com\/manual\/reference\/limits\/#indexes<\/a><\/p>\n<h2>List Indexes<\/h2>\n<pre class=\"line-numbers\"><code class=\"language-js\">db.message.getIndexes()\n\n\/\/ show collection statistics\ndb.message.stats()\ndb.message.stats().indexSizes\n\n\/\/ scale defaults to 1 to return size data in bytes\n\/\/ 1024 * 1024 means MB\ndb.getCollection('message').stats({'scale': 1024 * 1024}).indexSizes<\/code><\/pre>\n<p>ref:<br \/>\n<a href=\"https:\/\/docs.mongodb.com\/manual\/tutorial\/manage-indexes\/\">https:\/\/docs.mongodb.com\/manual\/tutorial\/manage-indexes\/<\/a><\/p>\n<h2>Add Indexes<\/h2>\n<p>TODO:<br \/>\nIt seems like creating indexes on empty collection, even with background will cause DB latency.<\/p>\n<p>An index which contains array fields might consume a lot of disk space.<\/p>\n<pre class=\"line-numbers\"><code class=\"language-js\">db.message.createIndex({\n    '_cls': 1,\n    'sender': 1,\n    'posted_at': 1\n}, {'background': true, 'sparse': true})\n\ndb.message.createIndex({\n    '_cls': 1,\n    'includes': 1,\n    'posted_at': 1\n}, {'background': true, 'sparse': true})\n\ndb.getCollection('message').find({\n    '$or': [\n        \/\/ sent by cp\n        {\n            '_cls': 'Message.ChatMessage',\n            'sender': ObjectId('582ee32a5b9c861c87dc297e'),\n            'posted_at': {\n                '$gte': ISODate('2018-01-08T00:00:00.000Z'),\n                '$lt': ISODate('2018-01-14T00:00:00.000Z')\n            }\n        },\n        \/\/ sent by payer\n        {\n            '_cls': 'Message.GiftMessage',\n            'includes': ObjectId('582ee32a5b9c861c87dc297e'),\n            'posted_at': {\n                '$gte': ISODate('2018-01-08T00:00:00.000Z'),\n                '$lt': ISODate('2018-01-14T00:00:00.000Z')\n            }\n        }\n    ]\n})<\/code><\/pre>\n<pre class=\"line-numbers\"><code class=\"language-py\">import pymongo\nfrom your_app.models import YourModel\n\nYourModel._get_collection().create_index(\n    [\n        ('users', pymongo.ASCENDING),\n        ('timestamp', pymongo.DESCENDING),\n    ], \n    background=True,\n    partialFilterExpression={'timestamp': {'$exists': True}},\n)<\/code><\/pre>\n<p>ref:<br \/>\n<a href=\"http:\/\/api.mongodb.com\/python\/current\/api\/pymongo\/collection.html#pymongo.collection.Collection.create_index\">http:\/\/api.mongodb.com\/python\/current\/api\/pymongo\/collection.html#pymongo.collection.Collection.create_index<\/a><\/p>\n<p>You can't index two arrays together, in this example: <code>includes<\/code> and <code>unlocks<\/code>.<\/p>\n<pre class=\"line-numbers\"><code class=\"language-js\">\/\/ it doesn't work\ndb.message.createIndex({\n    '_cls': 1,\n    'sender': 1,\n    'includes': 1,\n    'unlocks': 1\n}, {'background': true, 'sparse': true})<\/code><\/pre>\n<h3>The Order Of Fields of Compound Indexes<\/h3>\n<p>The order of fields in an index matters, you must consider <strong>Index Cardinality<\/strong> and <strong>Selectivity<\/strong>. Instead, the order of fields in a <code>find()<\/code> query or <code>$match<\/code> in an aggregation doesn't affect whether it can use an index or not.<\/p>\n<p>The order of fields in a compound index should be:<\/p>\n<ul>\n<li>First, fields on which you will query for exact values.<\/li>\n<li>Second, fields on which you will sort.<\/li>\n<li>Finally, fields on which you will query for a range of values.<\/li>\n<\/ul>\n<p>ref:<br \/>\n<a href=\"https:\/\/docs.mongodb.com\/manual\/core\/index-compound\/#prefixes\">https:\/\/docs.mongodb.com\/manual\/core\/index-compound\/#prefixes<\/a><br \/>\n<a href=\"https:\/\/emptysqua.re\/blog\/optimizing-mongodb-compound-indexes\/\">https:\/\/emptysqua.re\/blog\/optimizing-mongodb-compound-indexes\/<\/a><br \/>\n<a href=\"https:\/\/blog.mlab.com\/2012\/06\/cardinal-ins\/\">https:\/\/blog.mlab.com\/2012\/06\/cardinal-ins\/<\/a><br \/>\n<a href=\"https:\/\/stackoverflow.com\/questions\/33545339\/how-does-the-order-of-compound-indexes-matter-in-mongodb-performance-wise\">https:\/\/stackoverflow.com\/questions\/33545339\/how-does-the-order-of-compound-indexes-matter-in-mongodb-performance-wise<\/a><br \/>\n<a href=\"https:\/\/stackoverflow.com\/questions\/5245737\/mongodb-indexes-order-and-query-order-must-match\">https:\/\/stackoverflow.com\/questions\/5245737\/mongodb-indexes-order-and-query-order-must-match<\/a><\/p>\n<h3>Partial Indexes v.s. Sparse Indexes<\/h3>\n<p>Partial indexes should be preferred over sparse indexes. However, partial indexes only support a very small set of filter operators:<\/p>\n<ul>\n<li><code>$exists<\/code><\/li>\n<li><code>$eq<\/code> or <code>field: value<\/code><\/li>\n<li><code>$gt<\/code>, <code>$gte<\/code>, <code>$lt<\/code>, <code>$lte<\/code><\/li>\n<li><code>$type<\/code><\/li>\n<li><code>$and<\/code><\/li>\n<\/ul>\n<p>If you use <code>&#039;partialFilterExpression&#039;: {&#039;includes&#039;: {&#039;$exists&#039;: true}}<\/code>, MongoDB also indexes documents whose <code>includes<\/code> field has <code>null<\/code> value.<\/p>\n<pre class=\"line-numbers\"><code class=\"language-js\">db.collection('message').createIndex(\n    {'_cls': 1, 'includes': 1, 'posted_at': 1},\n    {'background': true, 'partialFilterExpression': {'includes': {'$exists': true}}}\n)\n\ndb.collection('message').createIndex(\n  {'created_at': -1},\n  {'background': true, 'partialFilterExpression': {'created_at': {'$gte': new Date(\"2018-01-01T16:00:00Z\")}}}\n)<\/code><\/pre>\n<p>ref:<br \/>\n<a href=\"https:\/\/docs.mongodb.com\/manual\/core\/index-partial\/\">https:\/\/docs.mongodb.com\/manual\/core\/index-partial\/<\/a><br \/>\n<a href=\"https:\/\/docs.mongodb.com\/manual\/core\/index-sparse\/\">https:\/\/docs.mongodb.com\/manual\/core\/index-sparse\/<\/a><\/p>\n<h3>Create An Index On An Array Field<\/h3>\n<p>Querying will certainly be a lot easier in an array field index than an object field.<\/p>\n<p>ref:<br \/>\n<a href=\"https:\/\/stackoverflow.com\/questions\/9589856\/mongo-indexing-on-object-arrays-vs-objects\">https:\/\/stackoverflow.com\/questions\/9589856\/mongo-indexing-on-object-arrays-vs-objects<\/a><\/p>\n<h3>Create An Unique Index On An Array Field<\/h3>\n<p>Create an unique index on an array field.<\/p>\n<p>The unique constraint applies to separate documents in the collection. That is, the unique index prevents separate documents from having the same value for the indexed key. It prevents different documents from having the same transaction ID but allows one document to have multiple identical transaction IDs.<\/p>\n<pre class=\"line-numbers\"><code class=\"language-js\">db.getCollection('test1').createIndex({purchases.transaction_id: 1}, {unique: true})\n\ndb.getCollection('test1').insert({ _id: 1, purchases: [\n    {transaction_id: 'A'}\n]})\n\ndb.getCollection('test1').insert({ _id: 5, purchases: [\n    {transaction_id: 'A'}\n]})\n\ndb.getCollection('test1').update({ _id: 1}, {$push: {purchases: {transaction_id: 'A'}}})<\/code><\/pre>\n<p>To prevent one document from having multiple identical transaction IDs, we would have atomic updates on single documents.<\/p>\n<pre class=\"line-numbers\"><code class=\"language-py\">user = User(id=bson.ObjectId(user_id))\npurchase = DirectPurchase(\n    user=user,\n    timestamp=timestamp,\n    transaction_id=transaction_id,\n)\nMessagePackProduct.objects \n    .filter(id=message_pack_id, __raw__={\n        'purchases': {'$not': {'$elemMatch': {\n            '_cls': purchase._cls,\n            'user': purchase.user.id,\n        }}},\n    }) \n    .update_one(push__purchases=purchase)<\/code><\/pre>\n<p>ref:<br \/>\n<a href=\"https:\/\/docs.mongodb.com\/manual\/core\/index-unique\/#unique-constraint-across-separate-documents\">https:\/\/docs.mongodb.com\/manual\/core\/index-unique\/#unique-constraint-across-separate-documents<\/a><\/p>\n<h3>Sort With Indexes<\/h3>\n<p>ref:<br \/>\n<a href=\"https:\/\/docs.mongodb.com\/manual\/tutorial\/sort-results-with-indexes\/\">https:\/\/docs.mongodb.com\/manual\/tutorial\/sort-results-with-indexes\/<\/a><\/p>\n<h2>Drop Indexes<\/h2>\n<pre class=\"line-numbers\"><code class=\"language-js\">db.message.dropIndex({\n    'includes': 1\n})\n\ndb.message.dropIndex({\n    '_cls': 1,\n    'posted_at': 1,\n    'includes': 1\n})<\/code><\/pre>\n<h3>Remove Unused Indexes<\/h3>\n<p>You can use <code>db.getCollection(&#039;COLLECTION_NAME&#039;).aggregate({$indexStats: {}})<\/code> to find unused indexes, there is a <code>accesses.ops<\/code> field which indicates the number of operations that have used the index. Also, you might want to remove indexes which have the same prefix.<\/p>\n<pre class=\"line-numbers\"><code class=\"language-js\">db.getCollection('message').aggregate(\n    {\n        '$indexStats': {}\n    },\n    {\n        '$match': {\n            'accesses.ops': {'$gt': 0}\n        }\n    }\n);<\/code><\/pre>\n<p>Result:<\/p>\n<pre class=\"line-numbers\"><code class=\"language-json\">{\n    \"name\" : \"_cls_1_sender_1_posted_at_1\",\n    \"key\" : {\n        \"_cls\" : 1,\n        \"sender\" : 1,\n        \"posted_at\" : 1\n    },\n    \"host\" : \"a6ea11893605:27017\",\n    \"accesses\" : {\n        \"ops\" : 3,\n        \"since\" : \"2018-01-26T07:04:51.137Z\"\n    }\n}<\/code><\/pre>\n<p>ref:<br \/>\n<a href=\"https:\/\/blog.mlab.com\/2017\/01\/using-mongodb-indexstats-to-identify-and-remove-unused-indexes\/\">https:\/\/blog.mlab.com\/2017\/01\/using-mongodb-indexstats-to-identify-and-remove-unused-indexes\/<\/a><br \/>\n<a href=\"https:\/\/scalegrid.io\/blog\/how-to-find-unused-indexes-in-mongodb\/\">https:\/\/scalegrid.io\/blog\/how-to-find-unused-indexes-in-mongodb\/<\/a><\/p>\n<h2>Profiling<\/h2>\n<pre class=\"line-numbers\"><code class=\"language-js\">\/\/ enable\ndb.setProfilingLevel(2)\n\n\/\/ disable\ndb.setProfilingLevel(0)\n\n\/\/ see profiling data after you issue some queries\ndb.system.profile.find().limit(10).sort( { ts : -1 } ).pretty()\n\n\/\/ delete profiling data\ndb.system.profile.drop()<\/code><\/pre>\n<h2>Query Explain<\/h2>\n<p>There are both <code>collection.find().explain()<\/code> and <code>collection.explain().find()<\/code>. It's recommended to use <code>collection.find().explain(&#039;executionStats&#039;)<\/code> for getting more information, like total documents examined.<\/p>\n<pre class=\"line-numbers\"><code class=\"language-js\">db.getCollection('message').find({\n    '$or': [\n        \/\/ sent by cp\n        {\n            '_cls': 'Message.ChatMessage',\n            'sender': ObjectId('582ee32a5b9c861c87dc297e'),\n            'posted_at': {\n                '$gte': ISODate('2018-01-08T00:00:00.000Z'),\n                '$lt': ISODate('2018-01-14T00:00:00.000Z')\n            }\n        },\n        {\n            '_cls': 'Message',\n            'sender': ObjectId('582ee32a5b9c861c87dc297e'),\n            'posted_at': {\n                '$gte': ISODate('2018-01-08T00:00:00.000Z'),\n                '$lt': ISODate('2018-01-14T00:00:00.000Z')\n            }\n        },\n        \/\/ sent by payer\n        {\n            '_cls': 'Message.ChatMessage',\n            'includes': ObjectId('582ee32a5b9c861c87dc297e'),\n            'posted_at': {\n                '$gte': ISODate('2018-01-08T00:00:00.000Z'),\n                '$lt': ISODate('2018-01-14T00:00:00.000Z')\n            }\n        },\n        {\n            '_cls': 'Message.ReplyMessage',\n            'includes': ObjectId('582ee32a5b9c861c87dc297e'),\n            'posted_at': {\n                '$gte': ISODate('2018-01-08T00:00:00.000Z'),\n                '$lt': ISODate('2018-01-14T00:00:00.000Z')\n            }\n        },\n        {\n            '_cls': 'Message.GiftMessage',\n            'includes': ObjectId('582ee32a5b9c861c87dc297e'),\n            'posted_at': {\n                '$gte': ISODate('2018-01-08T00:00:00.000Z'),\n                '$lt': ISODate('2018-01-14T00:00:00.000Z')\n            }\n        }\n    ]\n})\n\/\/ .explain()\n\/\/ .explain('allPlansExecution')\n.explain('executionStats')<\/code><\/pre>\n<p>ref:<br \/>\n<a href=\"https:\/\/docs.mongodb.com\/manual\/reference\/method\/cursor.explain\/\">https:\/\/docs.mongodb.com\/manual\/reference\/method\/cursor.explain\/<\/a><br \/>\n<a href=\"https:\/\/docs.mongodb.com\/manual\/reference\/method\/db.collection.explain\/#db.collection.explain\">https:\/\/docs.mongodb.com\/manual\/reference\/method\/db.collection.explain\/#db.collection.explain<\/a><\/p>\n<p>You could also explain a <code>.update()<\/code> query. However, <code>.updateMany()<\/code> and <code>.updateOne()<\/code> don't support <code>.explain()<\/code>.<\/p>\n<pre class=\"line-numbers\"><code class=\"language-js\">db.getCollection('user').explain().update(\n    {'follows.user': ObjectId(\"57985b784af4124063f090d3\")},\n    {'$set': {'created_at': ISODate('2018-01-01 00:00:00.000Z')}},\n    {'multi': true}\n)<\/code><\/pre>\n<p>Some important fields to look at in the result of <code>explain()<\/code>:<\/p>\n<ul>\n<li><code>executionStats.totalKeysExamined<\/code><\/li>\n<li><code>executionStats.totalDocsExamined<\/code><\/li>\n<li><code>queryPlanner.winningPlan.stage<\/code><\/li>\n<li><code>queryPlanner.winningPlan.inputStage.stage<\/code><\/li>\n<li><code>queryPlanner.winningPlan.inputStage.indexName<\/code><\/li>\n<li><code>queryPlanner.winningPlan.inputStage.direction<\/code><\/li>\n<\/ul>\n<p>Possible values of <code>stage<\/code>:<\/p>\n<ul>\n<li><code>COLLSCAN<\/code>: scanning the entire collection<\/li>\n<li><code>IXSCAN<\/code>: scanning index keys<\/li>\n<li><code>FETCH<\/code>: retrieving documents<\/li>\n<li><code>SHARD_MERGE<\/code>: merging results from shards<\/li>\n<\/ul>\n<p>ref:<br \/>\n<a href=\"https:\/\/docs.mongodb.com\/manual\/reference\/explain-results\/\">https:\/\/docs.mongodb.com\/manual\/reference\/explain-results\/<\/a><\/p>\n<h2>Aggregation Explain<\/h2>\n<pre class=\"line-numbers\"><code class=\"language-js\">db.getCollection('message').explain().aggregate()<\/code><\/pre>\n<p>ref:<br \/>\n<a href=\"https:\/\/stackoverflow.com\/questions\/12702080\/mongodb-explain-for-aggregation-framework\">https:\/\/stackoverflow.com\/questions\/12702080\/mongodb-explain-for-aggregation-framework<\/a><br \/>\n<a href=\"https:\/\/docs.mongodb.com\/manual\/reference\/method\/db.collection.explain\/\">https:\/\/docs.mongodb.com\/manual\/reference\/method\/db.collection.explain\/<\/a><\/p>\n<p>If <code>$project<\/code>, <code>$unwind<\/code>, or <code>$group<\/code> occur prior to the <code>$sort<\/code> operation, <code>$sort<\/code> cannot use any indexes. Additionally, <code>$sort<\/code> can only use fields defined in previous <code>$project<\/code> stage.<\/p>\n<p>Basically, you could just consider the <code>$match<\/code> part when you want to create new indexes.<\/p>\n<p>ref:<br \/>\n<a href=\"https:\/\/docs.mongodb.com\/manual\/reference\/operator\/aggregation\/sort\/#sort-operator-and-performance\">https:\/\/docs.mongodb.com\/manual\/reference\/operator\/aggregation\/sort\/#sort-operator-and-performance<\/a><\/p>\n<h2>MongoEngine<\/h2>\n<p><code>_cls<\/code> creation on indexes is automatically included if <code>allow_inheritance<\/code> is on. If you want to disable, set kwarg <code>cls: False<\/code>.<\/p>\n<p>ref:<br \/>\n<a href=\"http:\/\/docs.mongoengine.org\/guide\/defining-documents.html#indexes\">http:\/\/docs.mongoengine.org\/guide\/defining-documents.html#indexes<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>The order of fields in an index matters, you must consider Index Cardinality and Selectivity. Instead, the order of fields in a find() query doesn't affect whether it can use an index or not.<\/p>\n","protected":false},"author":1,"featured_media":515,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[22],"tags":[11,119,2],"class_list":["post-514","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-about-database","tag-javascript","tag-mongodb","tag-python"],"_links":{"self":[{"href":"https:\/\/vinta.ws\/code\/wp-json\/wp\/v2\/posts\/514","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/vinta.ws\/code\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/vinta.ws\/code\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/vinta.ws\/code\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/vinta.ws\/code\/wp-json\/wp\/v2\/comments?post=514"}],"version-history":[{"count":0,"href":"https:\/\/vinta.ws\/code\/wp-json\/wp\/v2\/posts\/514\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/vinta.ws\/code\/wp-json\/wp\/v2\/media\/515"}],"wp:attachment":[{"href":"https:\/\/vinta.ws\/code\/wp-json\/wp\/v2\/media?parent=514"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/vinta.ws\/code\/wp-json\/wp\/v2\/categories?post=514"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/vinta.ws\/code\/wp-json\/wp\/v2\/tags?post=514"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}