This repository has been archived by the owner on Nov 13, 2023. It is now read-only.
forked from cult-of-coders/grapher-docs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
db.json
1 lines (1 loc) · 442 KB
/
db.json
1
{"meta":{"version":1,"warehouse":"2.2.0"},"models":{"Asset":[{"_id":"themes/meteor/source/fonts/percolate.eot","path":"fonts/percolate.eot","modified":0,"renderable":1},{"_id":"themes/meteor/source/fonts/percolate.ttf","path":"fonts/percolate.ttf","modified":0,"renderable":1},{"_id":"themes/meteor/source/fonts/percolate.woff","path":"fonts/percolate.woff","modified":0,"renderable":1},{"_id":"themes/meteor/source/images/favicon.png","path":"images/favicon.png","modified":0,"renderable":1},{"_id":"themes/meteor/source/images/icon-white.svg","path":"images/icon-white.svg","modified":0,"renderable":1},{"_id":"themes/meteor/source/images/logo-coralspace-left.svg","path":"images/logo-coralspace-left.svg","modified":0,"renderable":1},{"_id":"themes/meteor/source/script/main.js","path":"script/main.js","modified":0,"renderable":1},{"_id":"themes/meteor/source/script/smooth-scroll.min.js","path":"script/smooth-scroll.min.js","modified":0,"renderable":1},{"_id":"themes/meteor/source/style/style.less","path":"style/style.less","modified":0,"renderable":1},{"_id":"themes/meteor/source/fonts/percolate.svg","path":"fonts/percolate.svg","modified":0,"renderable":1},{"_id":"themes/meteor/source/images/logo.png","path":"images/logo.png","modified":0,"renderable":1}],"Cache":[{"_id":"themes/meteor/.git","hash":"049265de896a0397e3c70e6313762e3c26f93523","modified":1474889374000},{"_id":"themes/meteor/_config.yaml","hash":"2bbc5bebc9a3102442c4d4b89d4ae0c829fd4e62","modified":1474889374000},{"_id":"source/index.md","hash":"b4c327c8e94b159a0d652908cd4e26baea6a272c","modified":1479730632271},{"_id":"source/commandline.md","hash":"0b329d957b5386c4280d372fcb876d29015ba01d","modified":1474889325000},{"_id":"themes/meteor/layout/layout.ejs","hash":"9c495eaef6bd651b5112cd99e2d98c1dc4fcf394","modified":1475835527000},{"_id":"themes/meteor/layout/page.ejs","hash":"55d520f94f170ebe7e3a144c1dc2a5edb32f5fe4","modified":1474889374000},{"_id":"source/api/accounts-multi.md","hash":"f86155b4d0ff6c8d9c3c5ad883c53eb6625c2b29","modified":1474889325000},{"_id":"source/api/accounts.md","hash":"2e04b2e0b51c4037d77aad2bbf6a5f82d3d922ec","modified":1474889325000},{"_id":"source/api/assets.md","hash":"23d669772ecc4ec8f1bd5d517bcd8a965fa78dbd","modified":1474889325000},{"_id":"source/api/blaze.md","hash":"d75884756afddfd2bc791c3e3384df73e71f70a9","modified":1474889325000},{"_id":"source/api/check.md","hash":"170d63a00796364506ee4397241062d2e276d454","modified":1474889325000},{"_id":"source/api/collections.md","hash":"1d715fc4a18cc8430248757fa37b14ce57b3730c","modified":1474889325000},{"_id":"source/api/connections.md","hash":"dd194f4c3b60bf51779e477580db9325a6dcaafb","modified":1474889325000},{"_id":"source/api/core.md","hash":"07aba32faf25ed16fc6442fa59ebaea2ececb16d","modified":1474889325000},{"_id":"source/api/ejson.md","hash":"626c38a1341ea12a3f957615e5200092b91963bf","modified":1474889325000},{"_id":"source/api/email.md","hash":"97a80f9b11f3c9d6bc7265201527d29bed77083f","modified":1474889325000},{"_id":"source/api/http.md","hash":"eb2a09d9f2d65120d688b47e42e1e06b4e153364","modified":1474889325000},{"_id":"source/api/methods.md","hash":"2a9c64efb7135baf43a9e88bc4fd06aa6040482d","modified":1474889325000},{"_id":"source/api/mobile-config.md","hash":"cc49bf8a8c411d91ca7f584e8761e7e3baeee5c9","modified":1474889325000},{"_id":"source/api/packagejs.md","hash":"2da4cb7c02733ed934172dd0ff6d66aafef79610","modified":1474889325000},{"_id":"source/api/pubsub.md","hash":"ebc3e8107cb22e75191bff600dfd36e43f12eab5","modified":1474889325000},{"_id":"source/api/passwords.md","hash":"d223dbc16d787843fdb10ef421d6f411b5bb1d79","modified":1474889325000},{"_id":"source/api/reactive-var.md","hash":"5eaff15aed6dfcfb87c12b0593a60e760d63e801","modified":1474889325000},{"_id":"source/api/session.md","hash":"de19fade87018a3a20a26d570feb8112d41daabe","modified":1474889325000},{"_id":"source/api/templates.md","hash":"149a1d828bd90b3b0e038d8a41b2ea5491751cb4","modified":1474889325000},{"_id":"source/api/timers.md","hash":"9ce32673bd46b7c61662ce708289a46237e6d4d4","modified":1474889325000},{"_id":"source/api/tracker.md","hash":"62b255f29d1201c116acc196ce6f76fb38abee25","modified":1474889325000},{"_id":"source/packages/accounts-ui.md","hash":"d39b2c6c7c31c45fa3f385d07f28ea9b1cb4431d","modified":1474889325000},{"_id":"source/packages/appcache.md","hash":"88d1f57aeb3c3b7ee3c54bf9a820d05ae644acaa","modified":1474889325000},{"_id":"source/packages/coffeescript.md","hash":"a00aceb918ea7d16331531960168af7795ed90ed","modified":1474889325000},{"_id":"source/packages/audit-argument-checks.md","hash":"14e35b60b49aff6bc6fd398f12e799e834289407","modified":1474889325000},{"_id":"source/packages/jquery.md","hash":"10866aa89a5a93b288342c00539e52922b6b6cc0","modified":1474889325000},{"_id":"source/packages/less.md","hash":"b4d4a20a5a96ffe17b7c5e4a72a1c79960730a2c","modified":1474889325000},{"_id":"source/packages/ecmascript.md","hash":"a000de71dc604eb453363540f8743b56feca7444","modified":1474889325000},{"_id":"source/packages/markdown.md","hash":"029caba5c4b521899f513d6eab2117ee4bbf1071","modified":1474889325000},{"_id":"source/packages/oauth-encryption.md","hash":"96d52e09c837cbb137752de21b749507f25d2820","modified":1474889325000},{"_id":"source/packages/modules.md","hash":"3c169bea0e926cdd28e2d2b040bae07de1d2ae53","modified":1474889325000},{"_id":"source/packages/random.md","hash":"b689a94ec85207d1fa7950a23294298bb0843680","modified":1474889325000},{"_id":"source/packages/spacebars.md","hash":"13454fe7dc69f4f741775fae978307151d8a8c2e","modified":1474889325000},{"_id":"source/packages/underscore.md","hash":"6d3cc369754de4d2b341032cd28bb8523aaebe92","modified":1474889325000},{"_id":"source/packages/webapp.md","hash":"8071b9ee8705fb99a8f236e2de3bf9ac2350d503","modified":1474889325000},{"_id":"themes/meteor/source/fonts/percolate.eot","hash":"9f46f6ed3453808cb206b5b8c7c399f8c7c50b4b","modified":1474889374000},{"_id":"themes/meteor/source/fonts/percolate.ttf","hash":"ae93904a100e0c875bb382cb88709de4cd8b6a37","modified":1474889374000},{"_id":"themes/meteor/source/fonts/percolate.woff","hash":"f475ff4ac3d777c8d56bc7040d6f8576b86398a5","modified":1474889374000},{"_id":"themes/meteor/source/images/favicon.png","hash":"c019ad5135fb00e9d5a8a000a7162f4876cf583b","modified":1474889374000},{"_id":"themes/meteor/source/images/icon-white.svg","hash":"037afdf5842532cdc696bd93541be8a273ddf9dc","modified":1474889374000},{"_id":"themes/meteor/source/images/logo-coralspace-left.svg","hash":"ce3fa809cc5498c23597f68fc7f94d72f0deb453","modified":1474889374000},{"_id":"themes/meteor/source/script/main.js","hash":"aa6f1d81ab38e3d8e0dbdef9a574d2330f8ff5a4","modified":1474889374000},{"_id":"themes/meteor/source/script/smooth-scroll.min.js","hash":"c80cccc6c68f32b348b3d8459eb89686871b2e38","modified":1474889374000},{"_id":"themes/meteor/source/style/style.less","hash":"6517fbcd0c75aeb1bd4fc6f0c9a834fcef9a77e1","modified":1474889374000},{"_id":"themes/meteor/layout/partials/illustration-help.ejs","hash":"03fcaff5811b72920c87fa9154ffc4853b30b8de","modified":1474889374000},{"_id":"themes/meteor/layout/partials/illustration-guide.ejs","hash":"f490bb8fd8e5abd0e71c97c92a335a0802e329e1","modified":1474889374000},{"_id":"themes/meteor/layout/partials/illustration-compass.ejs","hash":"8072852c211ea881b8facccbe00d975b2507d990","modified":1474889374000},{"_id":"themes/meteor/layout/partials/illustration-logs.ejs","hash":"47638a8a92ab5e5a7a143e1588ca9baaec371f9d","modified":1474889374000},{"_id":"themes/meteor/source/style/_global/panel.less","hash":"da39a3ee5e6b4b0d3255bfef95601890afd80709","modified":1474889374000},{"_id":"themes/meteor/layout/partials/illustration-support.ejs","hash":"4ac49bda616e8046bd4175fbb6e891dfcab658c0","modified":1474889374000},{"_id":"themes/meteor/layout/partials/illustration-github.ejs","hash":"ad171cc4d41acf187831c415cb1928d5ef7a1142","modified":1474889374000},{"_id":"themes/meteor/layout/partials/sidebar.ejs","hash":"76f12b19eab7b6a7e2fea15c66029613a1cb9163","modified":1474889374000},{"_id":"themes/meteor/source/fonts/percolate.svg","hash":"b7c6df677a47fd66316ce90839550bfad6fd462f","modified":1474889374000},{"_id":"themes/meteor/source/style/_global/Checkbox.less","hash":"9971b489264f4b37fb901cd8417accba7becf270","modified":1474889374000},{"_id":"themes/meteor/source/style/_global/Input.less","hash":"5be8dadb507ff338ae7cea539cae535b7779334c","modified":1474889374000},{"_id":"themes/meteor/source/style/_global/Textarea.less","hash":"4c6089bb5f41dde32d1828d6d27a0899f8e3c8cf","modified":1474889374000},{"_id":"themes/meteor/source/style/_global/Select.less","hash":"9065734a36e52c8ce2830d403da3852eebe3590c","modified":1474889374000},{"_id":"themes/meteor/source/style/_global/Radio.less","hash":"ecc255428e2883b49d074648a290de07b7a9d4d5","modified":1474889374000},{"_id":"themes/meteor/source/style/_global/animation.less","hash":"2c01fa20c282b133dda12a852fb61baba0c0af82","modified":1474889374000},{"_id":"themes/meteor/source/style/_global/base.less","hash":"0fce53b3187d99296dedd0fcd90887a4b336ad83","modified":1474889374000},{"_id":"themes/meteor/source/style/_global/button.less","hash":"d76568349602485c2ec7d0d3380091c4a5e8e2ca","modified":1474889374000},{"_id":"themes/meteor/source/style/_global/form.less","hash":"dcb4320c34011659a1e2974a7ae5b28b444cc519","modified":1474889374000},{"_id":"themes/meteor/source/style/_global/docsearch.less","hash":"26a087b4b6748822b7323584ba8dc375c7462641","modified":1474889374000},{"_id":"themes/meteor/source/style/_global/formatting.less","hash":"7d9dbfc393136e7a28fff7076f74bf5b7f3670cd","modified":1479731002537},{"_id":"themes/meteor/source/style/_global/icon.less","hash":"b6f93082065f57b48185c6fcbffafe5dfc98c86f","modified":1474889374000},{"_id":"themes/meteor/source/style/_global/mobile.less","hash":"d4f28dae69f89ce6e9646774ce6d07d6f677c683","modified":1474889374000},{"_id":"themes/meteor/source/style/_global/link.less","hash":"a80547ffbacd58422e7095aadbbd73ba0c650e31","modified":1474889374000},{"_id":"themes/meteor/source/style/_global/nav.less","hash":"e3eb2ec6e2245f6b4d40589c104618f9ed69f37f","modified":1474889374000},{"_id":"themes/meteor/source/style/_global/syntax.less","hash":"ff408a13d195a50b3310cdbf5ca31961393e7983","modified":1474889374000},{"_id":"themes/meteor/source/style/_theme/layout.less","hash":"655fcc41ad239d5a219aabc4c79c0ac970b6c8bd","modified":1474889374000},{"_id":"themes/meteor/source/style/_theme/panel.less","hash":"9438a41518ecdaa01d64ae65317ff6e27b03720d","modified":1474889374000},{"_id":"themes/meteor/source/style/_theme/nav.less","hash":"a558ca89e296a7e94d3a29e998aa119c877c065e","modified":1474889374000},{"_id":"themes/meteor/source/style/_theme/content.less","hash":"c90d7765335d1ee1eca5726ada84d7cb35a61745","modified":1474889374000},{"_id":"themes/meteor/source/style/_theme/sidebar.less","hash":"5fe1fb4c64bcf10d8bfe0caf63d2f969ed206a6c","modified":1474889374000},{"_id":"themes/meteor/source/style/_util/clearfix.import.less","hash":"8dd7f85394fc6e232cad232ea54e605a06be002e","modified":1474889374000},{"_id":"themes/meteor/source/style/_util/color.import.less","hash":"4bb122bdab82bc8aa154b1d8be72ca77fea23c8e","modified":1479730580594},{"_id":"themes/meteor/source/style/_util/easing.import.less","hash":"69523005d6afbd184cfa91d629cf1a931ebf8fd1","modified":1474889374000},{"_id":"themes/meteor/source/style/_util/helper.import.less","hash":"7baf147d5c4bac8c5ef4b2690af3b185b4df56d2","modified":1474889374000},{"_id":"themes/meteor/source/style/_util/link.import.less","hash":"a6856c0b5017b7bb688d7a2cf2d5f3bd682df6fe","modified":1474889374000},{"_id":"themes/meteor/source/style/_util/normalize.import.less","hash":"02fe53286d071637534d5aa2c57c76c168c0d521","modified":1474889374000},{"_id":"themes/meteor/source/style/_util/index.import.less","hash":"2a38f287116d66f9848229b59d03464b4f9b18b9","modified":1474889374000},{"_id":"themes/meteor/source/style/_util/scrollbar.import.less","hash":"1a45d8862fafd8d62f4e2562278a88ed3008ac32","modified":1474889374000},{"_id":"themes/meteor/source/style/_util/lesshat.import.less","hash":"491b7bc1426fb35bf17c28418aadab66b480b5e0","modified":1474889374000},{"_id":"themes/meteor/source/style/_util/text.import.less","hash":"3c1b4559dd5cf7b6b37a42ab8b7ebd9e40e2eee9","modified":1474889374000},{"_id":"themes/meteor/source/style/_util/ui.import.less","hash":"b577e1c8092b87f10baef86c0f9d30125b2cdf94","modified":1474889374000},{"_id":"themes/meteor/source/style/_util/typography.import.less","hash":"c8deee0f5ad8b529eeb097d90ef7a3f2f91441f6","modified":1474889374000},{"_id":"source/guide/exposure.md","hash":"35fe9df9a79ecf09f5049e860a6a618140ce4b67","modified":1479730817668},{"_id":"source/guide/links.md","hash":"f8b4eeefe6e5a2977c543ffdc6c751fbb00539ce","modified":1480411142968},{"_id":"source/guide/query.md","hash":"1ac3b0541a1387f79b2b97cd3f3e38111fd15d29","modified":1479737762524},{"_id":"source/api/collectionLinks.md","hash":"56d88ef0790046a8072cff0aace7eab16df4057b","modified":1474904935000},{"_id":"source/old_api/accounts-multi.md","hash":"f86155b4d0ff6c8d9c3c5ad883c53eb6625c2b29","modified":1474889325000},{"_id":"source/old_api/accounts.md","hash":"2e04b2e0b51c4037d77aad2bbf6a5f82d3d922ec","modified":1474889325000},{"_id":"source/old_api/assets.md","hash":"23d669772ecc4ec8f1bd5d517bcd8a965fa78dbd","modified":1474889325000},{"_id":"source/old_api/blaze.md","hash":"d75884756afddfd2bc791c3e3384df73e71f70a9","modified":1474889325000},{"_id":"source/old_api/check.md","hash":"170d63a00796364506ee4397241062d2e276d454","modified":1474889325000},{"_id":"source/old_api/collections.md","hash":"1d715fc4a18cc8430248757fa37b14ce57b3730c","modified":1474889325000},{"_id":"source/old_api/connections.md","hash":"dd194f4c3b60bf51779e477580db9325a6dcaafb","modified":1474889325000},{"_id":"source/old_api/core.md","hash":"07aba32faf25ed16fc6442fa59ebaea2ececb16d","modified":1474889325000},{"_id":"source/old_api/ejson.md","hash":"626c38a1341ea12a3f957615e5200092b91963bf","modified":1474889325000},{"_id":"source/old_api/email.md","hash":"97a80f9b11f3c9d6bc7265201527d29bed77083f","modified":1474889325000},{"_id":"source/old_api/http.md","hash":"eb2a09d9f2d65120d688b47e42e1e06b4e153364","modified":1474889325000},{"_id":"source/old_api/methods.md","hash":"2a9c64efb7135baf43a9e88bc4fd06aa6040482d","modified":1474889325000},{"_id":"source/old_api/mobile-config.md","hash":"cc49bf8a8c411d91ca7f584e8761e7e3baeee5c9","modified":1474889325000},{"_id":"source/old_api/packagejs.md","hash":"2da4cb7c02733ed934172dd0ff6d66aafef79610","modified":1474889325000},{"_id":"source/old_api/passwords.md","hash":"d223dbc16d787843fdb10ef421d6f411b5bb1d79","modified":1474889325000},{"_id":"source/old_api/pubsub.md","hash":"ebc3e8107cb22e75191bff600dfd36e43f12eab5","modified":1474889325000},{"_id":"source/old_api/reactive-var.md","hash":"5eaff15aed6dfcfb87c12b0593a60e760d63e801","modified":1474889325000},{"_id":"source/old_api/session.md","hash":"de19fade87018a3a20a26d570feb8112d41daabe","modified":1474889325000},{"_id":"source/old_api/templates.md","hash":"149a1d828bd90b3b0e038d8a41b2ea5491751cb4","modified":1474889325000},{"_id":"source/old_api/timers.md","hash":"9ce32673bd46b7c61662ce708289a46237e6d4d4","modified":1474889325000},{"_id":"source/old_api/tracker.md","hash":"62b255f29d1201c116acc196ce6f76fb38abee25","modified":1474889325000},{"_id":"source/api/collection.md","hash":"56d88ef0790046a8072cff0aace7eab16df4057b","modified":1474904935000},{"_id":"source/links/intro.md","hash":"22563ced472e63aac548720e73c40ab9afdc822b","modified":1474944651000},{"_id":"source/links/addLinks.md","hash":"fb9ff624d61dd6f7c3a801dc9efaafb726e768cf","modified":1474945427000},{"_id":"themes/meteor/source/images/logo.png","hash":"bb48a8becd78d3891642a96a6dcd6b499b14ad49","modified":1474785304000},{"_id":"source/api/reference.md","hash":"c9d62f4f296cda47e8d7fe9c867589cb8db8504d","modified":1476081598852},{"_id":"source/packages/boilerplate.md","hash":"b7a9d9e900c669f4143e10e9ef9fa1cf7d4748ef","modified":1479730853648},{"_id":"source/packages/live.md","hash":"8c9fc4a669c0719a0ae0ae6431cd1e865ad0eb62","modified":1479730853652},{"_id":"source/guide/namedQuery.md","hash":"67433ab7c4c02570e9c7342c10c68299ef4113a6","modified":1479730817672},{"_id":"public/packages/boilerplate.html","hash":"3842a2cbbbb4f4bd49ae0d83b8a057ffdffee96e","modified":1479737915533},{"_id":"public/packages/live.html","hash":"dcf82dc4ec7a66a1a751d31b328fa66109a1a99e","modified":1479737915534},{"_id":"public/index.html","hash":"65fed0fbe15f9cfcb903f38fd38b13070eeedd8f","modified":1479737915533},{"_id":"public/guide/links.html","hash":"8fb670092760387d11cb15c1cf0cca394f0451ab","modified":1480411223411},{"_id":"public/guide/query.html","hash":"5f833682ffec6424a79661ebfd9d9dba9d911ca0","modified":1479737915534},{"_id":"public/api/reference.html","hash":"5804cc3431b97d6f22e75bdcaf78a97a7f1ce98c","modified":1476085992422},{"_id":"public/guide/exposure.html","hash":"9209cf8d64d73a57c396ebd55b93f58c33822459","modified":1479737915534},{"_id":"public/guide/namedQuery.html","hash":"f279c644017493497ffc28756482d8a69e52d6dd","modified":1479737915534},{"_id":"source/api/exposure.md","hash":"058dc4a6556db3249be5d18b743b90571ff1f7d6","modified":1479730654299},{"_id":"source/api/namedQuery.md","hash":"f09c03593d1671c00d89079fefca6ac4482a2c04","modified":1479730682267},{"_id":"source/api/links.md","hash":"a126cf24b44b533d86568142c013a7eed4077b2d","modified":1479730671883},{"_id":"source/api/query.md","hash":"e128334479c3d01e6ff76740a642312dd1b02dc9","modified":1480411142964},{"_id":"public/api/exposure.html","hash":"e767dbeb927844f9cb1ad8f76f067e5d4209633e","modified":1479737915534},{"_id":"public/api/namedQuery.html","hash":"0c3c28e5a80c915d5d645c29ef6eb84d6c77666c","modified":1479737915534},{"_id":"public/api/links.html","hash":"96d21de961f154c4eb448deeed1a335b1c7f9020","modified":1479737915534},{"_id":"public/api/query.html","hash":"a8e6899ccc429dc5d9155f7dd77de5f9327c112d","modified":1480411223411},{"_id":"public/fonts/percolate.eot","hash":"9f46f6ed3453808cb206b5b8c7c399f8c7c50b4b","modified":1479737915538},{"_id":"public/fonts/percolate.ttf","hash":"ae93904a100e0c875bb382cb88709de4cd8b6a37","modified":1479737915538},{"_id":"public/fonts/percolate.woff","hash":"f475ff4ac3d777c8d56bc7040d6f8576b86398a5","modified":1479737915538},{"_id":"public/images/favicon.png","hash":"c019ad5135fb00e9d5a8a000a7162f4876cf583b","modified":1479737915538},{"_id":"public/images/icon-white.svg","hash":"037afdf5842532cdc696bd93541be8a273ddf9dc","modified":1479737915538},{"_id":"public/images/logo-coralspace-left.svg","hash":"ce3fa809cc5498c23597f68fc7f94d72f0deb453","modified":1479737915538},{"_id":"public/images/logo.png","hash":"bb48a8becd78d3891642a96a6dcd6b499b14ad49","modified":1479737915539},{"_id":"public/script/main.js","hash":"aa6f1d81ab38e3d8e0dbdef9a574d2330f8ff5a4","modified":1479737915555},{"_id":"public/script/smooth-scroll.min.js","hash":"c80cccc6c68f32b348b3d8459eb89686871b2e38","modified":1479737915555},{"_id":"public/fonts/percolate.svg","hash":"b7c6df677a47fd66316ce90839550bfad6fd462f","modified":1479737915556},{"_id":"public/style/style.css","hash":"7239171944b755f015074bd08e903bcce2d4233e","modified":1479737915847}],"Category":[],"Data":[],"Page":[{"title":"Introduction","description":"Grapher is a collection relationship manager and a secure data fetcher.","_content":"\n## What is Grapher?\n\nGrapher is a Meteor package that:\n\n- Allows Collections Relationship Management with an easy and intuitive API\n- Allows you to securely expose collections client-side\n- Allows you to fetch the data graph using JS objects as your request\n- Offers the same API for Reactive and Non-Reactive queries\n- Integrates with your existing Meteor projects, already existing MongoDB relations and SimpleSchema\n\n## LTS version: 1.2 until 2020\n\nGrapher version 1.2 now has long-term support until 2020.\n\n## Installation\n\n```bash\nmeteor add cultofcoders:grapher\n```\n\n## Read The Guide\n\n- [Managing Links](/guide/links.html)\n- [Exposing Collections](/guide/exposure.html)\n- [Queries](/guide/query.html)\n- [Named Queries](/guide/namedQuery.html)\n\n## Boilerplate\n\nA meteor project with some links setup and grapher-live integrated.\n\n```bash\ngit clone https://github.com/cult-of-coders/grapher-boilerplate\n```\n\n[Read more](/packages/boilerplate.html)\n\n## Grapher-Live\n\nView documentation and test your queries live.\n\n[Read more](/packages/live.html)\n","source":"index.md","raw":"---\ntitle: Introduction\ndescription: Grapher is a collection relationship manager and a secure data fetcher.\n---\n\n## What is Grapher?\n\nGrapher is a Meteor package that:\n\n- Allows Collections Relationship Management with an easy and intuitive API\n- Allows you to securely expose collections client-side\n- Allows you to fetch the data graph using JS objects as your request\n- Offers the same API for Reactive and Non-Reactive queries\n- Integrates with your existing Meteor projects, already existing MongoDB relations and SimpleSchema\n\n## LTS version: 1.2 until 2020\n\nGrapher version 1.2 now has long-term support until 2020.\n\n## Installation\n\n```bash\nmeteor add cultofcoders:grapher\n```\n\n## Read The Guide\n\n- [Managing Links](/guide/links.html)\n- [Exposing Collections](/guide/exposure.html)\n- [Queries](/guide/query.html)\n- [Named Queries](/guide/namedQuery.html)\n\n## Boilerplate\n\nA meteor project with some links setup and grapher-live integrated.\n\n```bash\ngit clone https://github.com/cult-of-coders/grapher-boilerplate\n```\n\n[Read more](/packages/boilerplate.html)\n\n## Grapher-Live\n\nView documentation and test your queries live.\n\n[Read more](/packages/live.html)\n","date":"2016-11-21T12:17:12.271Z","updated":"2016-11-21T12:17:12.271Z","path":"index.html","_id":"citjzdojc0000awjxzf35hp0l","comments":1,"layout":"page","content":"<h2 id=\"What-is-Grapher\"><a href=\"#What-is-Grapher\" class=\"headerlink\" title=\"What is Grapher?\"></a>What is Grapher?</h2><p>Grapher is a Meteor package that:</p>\n<ul>\n<li>Allows Collections Relationship Management with an easy and intuitive API</li>\n<li>Allows you to securely expose collections client-side</li>\n<li>Allows you to fetch the data graph using JS objects as your request</li>\n<li>Offers the same API for Reactive and Non-Reactive queries</li>\n<li>Integrates with your existing Meteor projects, already existing MongoDB relations and SimpleSchema</li>\n</ul>\n<h2 id=\"LTS-version-1-2-until-2020\"><a href=\"#LTS-version-1-2-until-2020\" class=\"headerlink\" title=\"LTS version: 1.2 until 2020\"></a>LTS version: 1.2 until 2020</h2><p>Grapher version 1.2 now has long-term support until 2020.</p>\n<h2 id=\"Installation\"><a href=\"#Installation\" class=\"headerlink\" title=\"Installation\"></a>Installation</h2><figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\">meteor add cultofcoders:grapher</div></pre></td></tr></table></figure>\n<h2 id=\"Read-The-Guide\"><a href=\"#Read-The-Guide\" class=\"headerlink\" title=\"Read The Guide\"></a>Read The Guide</h2><ul>\n<li><a href=\"/guide/links.html\">Managing Links</a></li>\n<li><a href=\"/guide/exposure.html\">Exposing Collections</a></li>\n<li><a href=\"/guide/query.html\">Queries</a></li>\n<li><a href=\"/guide/namedQuery.html\">Named Queries</a></li>\n</ul>\n<h2 id=\"Boilerplate\"><a href=\"#Boilerplate\" class=\"headerlink\" title=\"Boilerplate\"></a>Boilerplate</h2><p>A meteor project with some links setup and grapher-live integrated.</p>\n<figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\">git <span class=\"built_in\">clone</span> https://github.com/cult-of-coders/grapher-boilerplate</div></pre></td></tr></table></figure>\n<p><a href=\"/packages/boilerplate.html\">Read more</a></p>\n<h2 id=\"Grapher-Live\"><a href=\"#Grapher-Live\" class=\"headerlink\" title=\"Grapher-Live\"></a>Grapher-Live</h2><p>View documentation and test your queries live.</p>\n<p><a href=\"/packages/live.html\">Read more</a></p>\n","excerpt":"","more":"<h2 id=\"What-is-Grapher\"><a href=\"#What-is-Grapher\" class=\"headerlink\" title=\"What is Grapher?\"></a>What is Grapher?</h2><p>Grapher is a Meteor package that:</p>\n<ul>\n<li>Allows Collections Relationship Management with an easy and intuitive API</li>\n<li>Allows you to securely expose collections client-side</li>\n<li>Allows you to fetch the data graph using JS objects as your request</li>\n<li>Offers the same API for Reactive and Non-Reactive queries</li>\n<li>Integrates with your existing Meteor projects, already existing MongoDB relations and SimpleSchema</li>\n</ul>\n<h2 id=\"LTS-version-1-2-until-2020\"><a href=\"#LTS-version-1-2-until-2020\" class=\"headerlink\" title=\"LTS version: 1.2 until 2020\"></a>LTS version: 1.2 until 2020</h2><p>Grapher version 1.2 now has long-term support until 2020.</p>\n<h2 id=\"Installation\"><a href=\"#Installation\" class=\"headerlink\" title=\"Installation\"></a>Installation</h2><figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\">meteor add cultofcoders:grapher</div></pre></td></tr></table></figure>\n<h2 id=\"Read-The-Guide\"><a href=\"#Read-The-Guide\" class=\"headerlink\" title=\"Read The Guide\"></a>Read The Guide</h2><ul>\n<li><a href=\"/guide/links.html\">Managing Links</a></li>\n<li><a href=\"/guide/exposure.html\">Exposing Collections</a></li>\n<li><a href=\"/guide/query.html\">Queries</a></li>\n<li><a href=\"/guide/namedQuery.html\">Named Queries</a></li>\n</ul>\n<h2 id=\"Boilerplate\"><a href=\"#Boilerplate\" class=\"headerlink\" title=\"Boilerplate\"></a>Boilerplate</h2><p>A meteor project with some links setup and grapher-live integrated.</p>\n<figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\">git <span class=\"built_in\">clone</span> https://github.com/cult-of-coders/grapher-boilerplate</div></pre></td></tr></table></figure>\n<p><a href=\"/packages/boilerplate.html\">Read more</a></p>\n<h2 id=\"Grapher-Live\"><a href=\"#Grapher-Live\" class=\"headerlink\" title=\"Grapher-Live\"></a>Grapher-Live</h2><p>View documentation and test your queries live.</p>\n<p><a href=\"/packages/live.html\">Read more</a></p>\n"},{"title":"Using Query","description":"How to create and fetch queries","_content":"\n## Introduction\n\nQueries are a way to specify which data you want from the server using links as the backbone for creating the data graph.\nQueries can be reactive (using Meteor's pub/sub system) or static (using method call) or direct if the call is done server side.\n\nLet's configure some links, and then see how we can query them into the database.\n\nAssuming we have these collections: Authors, Comments, Posts, Groups, Category:\n\n- Author has many posts.\n- Author can belong in many groups.\n- Posts has many comments.\n- Posts has one category.\n- Comments has a single author.\n\n### Don't panic! \nWe'll start defining our links, if something stops making sense. Review the [Collection Links](/guide/links.html) documentation again.\n\n```js\nAuthors.addLinks({\n groups: {\n collection: Groups,\n field: 'groupIds',\n type: 'many'\n },\n posts: {\n collection: Posts,\n inversedBy: 'author'\n },\n // Resolver links only work on server-side or with non-reactive queries\n likesOnFacebook: {\n // in this case resolver will receive: object, filters, options, userId\n // since resolver is run server side, the author will be the full object with all the fields.\n resolve(author) {\n // do a sync call to retrieve the likes on facebook using author object.\n return count;\n }\n }\n});\n\nPosts.addLinks({\n author: {\n collection: Authors,\n type: 'one',\n field: 'authorId'\n },\n // it can have a lot of comments, so it's safer if we store the link in Comments collection\n comments: { \n collection: Comments,\n inversedBy: 'post'\n },\n category: {\n collection: Categories,\n type: 'many',\n field: 'categoryIds'\n }\n});\n\nComments.addLinks({\n author: {\n collection: Authors,\n field: 'authorId'\n },\n post: {\n collection: Posts,\n field: 'postId'\n }\n});\n\nCategory.addLinks({\n author: {\n collection: Authors,\n inversedBy: 'category',\n }\n});\n\nGroups.addLinks({\n authors: {\n collection: Authors,\n inversedBy: 'groups'\n }\n});\n```\n\nPerfect. Now that we defined our relationships we can query our database.\nAssuming we exposed \"Posts\" server-side, we can fetch the query client-side.\n\n{% pullquote 'warning' %}\nNotes:\n\n- Use {} to specify a link, and 1 for a field.\n- \"_id\" will always be fetched\n- You must always specify the fields you need, otherwise it will only fetch _id\n{% endpullquote %}\n\n\n```js\nconst query = Posts.createQuery({\n title: 1,\n // if there are no custom fields specified, it will retrieve all fields.\n author: {\n // if you have a nested object, (no link named profile) it will not try to fetch the link, but rather give you only the fields you need.\n profile: {\n firstname: 1\n lastname: 1\n },\n likesOnFacebook: 1\n } \n comments: {\n text: 1,\n // if you don't specify any local fields for the author, only \"_id\" field will be fetched\n // this will enforce the use of query and retrieve only the data you need.\n author: {\n groups: {\n name: 1\n }\n }\n }\n});\n```\n\nNow that we have created our query, we have two options of fetching the data.\n\n## Static Queries\n\nStatic methods receive their data using a method call to the exposure.\n\n```js\nquery.fetch((error, response) => {\n // if no error occured, the response will look something like this\n [\n {\n _id: 'XXXXXXXXXXXXXXX',\n title: 'Hello World!',\n author: {\n profile: {\n firstname: 'John',\n lastname: 'Smith'\n }\n likesOnFacebook: 200\n },\n comments: [\n {\n text: 'Nice Post',\n author: {\n _id: 'XXXXXXXXXXXXX'\n },\n groups: [\n {\n _id: 'XXXXXXXXXXX',\n name: 'Group 1'\n }\n ]\n }\n ]\n },\n ...\n ]\n});\n```\n\n## Reactive Queries\n\n```js\nconst subsHandle = query.subscribe();\nconst data = query.fetch();\n\nquery.unsubscribe();\nquery.fetch(); // now it will fail because you did not provide a callback, because when you unsubscribe, we delete the subscriptionHandle\n```\n\n\n{% pullquote 'warning' %}\nImportant! If you previously subscribed, fetching will be done client side using client-side collections,\nif you did not previously subscribe, you need to provide a callback because data will be fetched via a method call.\n{% endpullquote %}\n\nIf you don't want to use .fetch() you can also use the collections as you previously used to:\n\n```js\nPosts.find().fetch()\nComments.find({postId: 'XXXXXX'}).fetch()\n```\n\n\n## Creating a query without the collection object\n\n```js\nimport { createQuery } from 'meteor/cultofcoders:grapher';\n\ncreateQuery({\n posts: {\n comments: {\n text: 1\n }\n }\n});\n```\n\n*posts* is the name of the collection, specified as the first parameter in the *Mongo.Collection* constructor.\n\n## $filters and $options\n\nAt any given collection node in your query you can specify different filtering techniques.\n\nAvailable $filters: http://docs.meteor.com/api/collections.html#selectors\n\nAvailable $options: *sort*, *skip* and *limit* \nRead more: http://docs.meteor.com/api/collections.html#Mongo-Collection-find\n\n```js\nconst query = Posts.createQuery({\n $filters: {isApproved: true} // this will find only posts that have isApproved: true\n $options: {\n limit: 100\n }\n title: 1\n comments: {\n $filters: { // this will only search the comments that have isNotSpam: true\n isNotSpam: true\n }\n }\n});\n```\n\n## Parameters\n\nYou can pass params to your query, they will be available in every $filter() function.\nUsing $filter() gives you enough control to filters and options. So $filters and $options may be omitted.\n\n```js\nconst query = Posts.createQuery({\n $filter({filters, options, params}) {\n filters.isApproved = params.isApproved\n }\n title: 1\n comments: {\n $filter({filters, options, params}) {\n if (params.allowSpamComments) {\n filters.isNotSpam = undefined; // $filter() overrides $filters and $options\n }\n }\n $filters: { // this will only search the comments that have isNotSpam: true\n isNotSpam: true\n }\n }\n}, {\n isApproved: true,\n allowSpamComments: true\n});\n\n```\n\nControl parameters however you wish:\n```js\nquery.setParams({\n allowSpamComments: false\n});\n```\n\nUsing it with *React* and *react-meteor-data* package:\n\n```js\nimport { createContainer } from 'meteor/react-meteor-data';\nimport query from './listPostsQuery.js';\n\nconst localQuery = query.clone();\n\nexport default createContainer(() => {\n const handle = localQuery.subscribe();\n const posts = localQuery.fetch();\n \n return {\n isReady: handle.isReady(),\n posts: posts\n }\n}, PostList);\n```\n\n{% pullquote 'warning' %}\nWe use .clone() method to avoid making changes on the actual query (like setParams). \nYou could do is export a factory that creates your query on the fly, however, for simplicity,\nwe created a .clone() method, that clones the query and it is completely isolated.\n{% endpullquote %}\n\n{% pullquote 'warning' %}\nWhen you have metadata links. A $metadata object will be stored to the children referncing the $metadata from the parent.\n{% endpullquote %}\n\n## Reducers\n\n### Basic\n\nReducers are a way of combining the data from your graph request. Best to show an example:\n```\n// setting up\nUsers.addReducers({\n fullName: { // the name of how you want to request it\n body: { // the dependency, what info it needs to be able to reduce\n profile: {\n firstName: 1,\n lastName: 1\n }\n },\n reduce(object) { // a pure function that returns the data\n return object.profile.firstName + ' ' + object.profile.lastName;\n }\n }\n})\n```\n\n```\n// usage\ncreateQuery({\n users: {\n fullName: 1\n }\n})\n```\n\n### Reducers can make use of links\n\nEasily grab the data from your links, if you want to reduce it.\n\n```\nUsers.addReducers({\n groups: { // the name of how you want to request it\n body: {\n groups: { name: 1 } // assuming you have a link called groups\n },\n reduce(object) { // a pure function that returns the data\n return object.groups.map(group => group.name).join(',')\n }\n }\n})\n```\n\n### Reducers can use other reducers\n\n```\n// setting up\nUsers.addReducers({\n fullNameWithRoles: { // the name of how you want to request it\n body: { // the dependency, what info it needs to be able to reduce\n fullName: 1,\n roles: 1\n },\n reduce(object) { // a pure function that returns the data\n return object.fullName + object.roles.join(',');\n }\n }\n})\n```\n\n\n{% pullquote 'warning' %}\nIf you do not explicitly request the fields that the reducer needs, they will not be present in your response.\n{% endpullquote %}\n\n## Security and Performance\n\nBy default the options \"disableOplog\", \"pollingIntervalMs\", \"pollingThrottleMs\" are not available on the client.\nYou can control them in the firewall of your exposure.\n\nGrapher is very performant. To understand what we're talking about let's take this example:\n```js\n{\n users: {\n posts: {\n comments: {\n author: {}\n }\n }\n }\n}\n```\n\nFor a query like this, if we would've first received the users, then the posts for each user, then the comments for each post, then the author for each comments.\nWe would've blasted MongoDB with a lot of queries, and the number of queries increases exponentially. It can easily be around ~2000 for a simple query.\n\nHowever, using the *Hypernova* module, an innovative approach, the query above is executed with only 4 queries. \nBecause we have 4 collection nodes: \"users\", \"posts\", \"comments\" and \"author\"\n\nIt does this by aggregating filters and reassembles data locally.\n\nFrom 2000 queries to 4 queries we experienced around 40x percent performance boost. \n\n## React Integration\nFor integration with React try out [cultofcoders:grapher-react](https://github.com/cult-of-coders/grapher-react) package\n\n","source":"guide/query.md","raw":"---\ntitle: Using Query\ndescription: How to create and fetch queries\n---\n\n## Introduction\n\nQueries are a way to specify which data you want from the server using links as the backbone for creating the data graph.\nQueries can be reactive (using Meteor's pub/sub system) or static (using method call) or direct if the call is done server side.\n\nLet's configure some links, and then see how we can query them into the database.\n\nAssuming we have these collections: Authors, Comments, Posts, Groups, Category:\n\n- Author has many posts.\n- Author can belong in many groups.\n- Posts has many comments.\n- Posts has one category.\n- Comments has a single author.\n\n### Don't panic! \nWe'll start defining our links, if something stops making sense. Review the [Collection Links](/guide/links.html) documentation again.\n\n```js\nAuthors.addLinks({\n groups: {\n collection: Groups,\n field: 'groupIds',\n type: 'many'\n },\n posts: {\n collection: Posts,\n inversedBy: 'author'\n },\n // Resolver links only work on server-side or with non-reactive queries\n likesOnFacebook: {\n // in this case resolver will receive: object, filters, options, userId\n // since resolver is run server side, the author will be the full object with all the fields.\n resolve(author) {\n // do a sync call to retrieve the likes on facebook using author object.\n return count;\n }\n }\n});\n\nPosts.addLinks({\n author: {\n collection: Authors,\n type: 'one',\n field: 'authorId'\n },\n // it can have a lot of comments, so it's safer if we store the link in Comments collection\n comments: { \n collection: Comments,\n inversedBy: 'post'\n },\n category: {\n collection: Categories,\n type: 'many',\n field: 'categoryIds'\n }\n});\n\nComments.addLinks({\n author: {\n collection: Authors,\n field: 'authorId'\n },\n post: {\n collection: Posts,\n field: 'postId'\n }\n});\n\nCategory.addLinks({\n author: {\n collection: Authors,\n inversedBy: 'category',\n }\n});\n\nGroups.addLinks({\n authors: {\n collection: Authors,\n inversedBy: 'groups'\n }\n});\n```\n\nPerfect. Now that we defined our relationships we can query our database.\nAssuming we exposed \"Posts\" server-side, we can fetch the query client-side.\n\n{% pullquote 'warning' %}\nNotes:\n\n- Use {} to specify a link, and 1 for a field.\n- \"_id\" will always be fetched\n- You must always specify the fields you need, otherwise it will only fetch _id\n{% endpullquote %}\n\n\n```js\nconst query = Posts.createQuery({\n title: 1,\n // if there are no custom fields specified, it will retrieve all fields.\n author: {\n // if you have a nested object, (no link named profile) it will not try to fetch the link, but rather give you only the fields you need.\n profile: {\n firstname: 1\n lastname: 1\n },\n likesOnFacebook: 1\n } \n comments: {\n text: 1,\n // if you don't specify any local fields for the author, only \"_id\" field will be fetched\n // this will enforce the use of query and retrieve only the data you need.\n author: {\n groups: {\n name: 1\n }\n }\n }\n});\n```\n\nNow that we have created our query, we have two options of fetching the data.\n\n## Static Queries\n\nStatic methods receive their data using a method call to the exposure.\n\n```js\nquery.fetch((error, response) => {\n // if no error occured, the response will look something like this\n [\n {\n _id: 'XXXXXXXXXXXXXXX',\n title: 'Hello World!',\n author: {\n profile: {\n firstname: 'John',\n lastname: 'Smith'\n }\n likesOnFacebook: 200\n },\n comments: [\n {\n text: 'Nice Post',\n author: {\n _id: 'XXXXXXXXXXXXX'\n },\n groups: [\n {\n _id: 'XXXXXXXXXXX',\n name: 'Group 1'\n }\n ]\n }\n ]\n },\n ...\n ]\n});\n```\n\n## Reactive Queries\n\n```js\nconst subsHandle = query.subscribe();\nconst data = query.fetch();\n\nquery.unsubscribe();\nquery.fetch(); // now it will fail because you did not provide a callback, because when you unsubscribe, we delete the subscriptionHandle\n```\n\n\n{% pullquote 'warning' %}\nImportant! If you previously subscribed, fetching will be done client side using client-side collections,\nif you did not previously subscribe, you need to provide a callback because data will be fetched via a method call.\n{% endpullquote %}\n\nIf you don't want to use .fetch() you can also use the collections as you previously used to:\n\n```js\nPosts.find().fetch()\nComments.find({postId: 'XXXXXX'}).fetch()\n```\n\n\n## Creating a query without the collection object\n\n```js\nimport { createQuery } from 'meteor/cultofcoders:grapher';\n\ncreateQuery({\n posts: {\n comments: {\n text: 1\n }\n }\n});\n```\n\n*posts* is the name of the collection, specified as the first parameter in the *Mongo.Collection* constructor.\n\n## $filters and $options\n\nAt any given collection node in your query you can specify different filtering techniques.\n\nAvailable $filters: http://docs.meteor.com/api/collections.html#selectors\n\nAvailable $options: *sort*, *skip* and *limit* \nRead more: http://docs.meteor.com/api/collections.html#Mongo-Collection-find\n\n```js\nconst query = Posts.createQuery({\n $filters: {isApproved: true} // this will find only posts that have isApproved: true\n $options: {\n limit: 100\n }\n title: 1\n comments: {\n $filters: { // this will only search the comments that have isNotSpam: true\n isNotSpam: true\n }\n }\n});\n```\n\n## Parameters\n\nYou can pass params to your query, they will be available in every $filter() function.\nUsing $filter() gives you enough control to filters and options. So $filters and $options may be omitted.\n\n```js\nconst query = Posts.createQuery({\n $filter({filters, options, params}) {\n filters.isApproved = params.isApproved\n }\n title: 1\n comments: {\n $filter({filters, options, params}) {\n if (params.allowSpamComments) {\n filters.isNotSpam = undefined; // $filter() overrides $filters and $options\n }\n }\n $filters: { // this will only search the comments that have isNotSpam: true\n isNotSpam: true\n }\n }\n}, {\n isApproved: true,\n allowSpamComments: true\n});\n\n```\n\nControl parameters however you wish:\n```js\nquery.setParams({\n allowSpamComments: false\n});\n```\n\nUsing it with *React* and *react-meteor-data* package:\n\n```js\nimport { createContainer } from 'meteor/react-meteor-data';\nimport query from './listPostsQuery.js';\n\nconst localQuery = query.clone();\n\nexport default createContainer(() => {\n const handle = localQuery.subscribe();\n const posts = localQuery.fetch();\n \n return {\n isReady: handle.isReady(),\n posts: posts\n }\n}, PostList);\n```\n\n{% pullquote 'warning' %}\nWe use .clone() method to avoid making changes on the actual query (like setParams). \nYou could do is export a factory that creates your query on the fly, however, for simplicity,\nwe created a .clone() method, that clones the query and it is completely isolated.\n{% endpullquote %}\n\n{% pullquote 'warning' %}\nWhen you have metadata links. A $metadata object will be stored to the children referncing the $metadata from the parent.\n{% endpullquote %}\n\n## Reducers\n\n### Basic\n\nReducers are a way of combining the data from your graph request. Best to show an example:\n```\n// setting up\nUsers.addReducers({\n fullName: { // the name of how you want to request it\n body: { // the dependency, what info it needs to be able to reduce\n profile: {\n firstName: 1,\n lastName: 1\n }\n },\n reduce(object) { // a pure function that returns the data\n return object.profile.firstName + ' ' + object.profile.lastName;\n }\n }\n})\n```\n\n```\n// usage\ncreateQuery({\n users: {\n fullName: 1\n }\n})\n```\n\n### Reducers can make use of links\n\nEasily grab the data from your links, if you want to reduce it.\n\n```\nUsers.addReducers({\n groups: { // the name of how you want to request it\n body: {\n groups: { name: 1 } // assuming you have a link called groups\n },\n reduce(object) { // a pure function that returns the data\n return object.groups.map(group => group.name).join(',')\n }\n }\n})\n```\n\n### Reducers can use other reducers\n\n```\n// setting up\nUsers.addReducers({\n fullNameWithRoles: { // the name of how you want to request it\n body: { // the dependency, what info it needs to be able to reduce\n fullName: 1,\n roles: 1\n },\n reduce(object) { // a pure function that returns the data\n return object.fullName + object.roles.join(',');\n }\n }\n})\n```\n\n\n{% pullquote 'warning' %}\nIf you do not explicitly request the fields that the reducer needs, they will not be present in your response.\n{% endpullquote %}\n\n## Security and Performance\n\nBy default the options \"disableOplog\", \"pollingIntervalMs\", \"pollingThrottleMs\" are not available on the client.\nYou can control them in the firewall of your exposure.\n\nGrapher is very performant. To understand what we're talking about let's take this example:\n```js\n{\n users: {\n posts: {\n comments: {\n author: {}\n }\n }\n }\n}\n```\n\nFor a query like this, if we would've first received the users, then the posts for each user, then the comments for each post, then the author for each comments.\nWe would've blasted MongoDB with a lot of queries, and the number of queries increases exponentially. It can easily be around ~2000 for a simple query.\n\nHowever, using the *Hypernova* module, an innovative approach, the query above is executed with only 4 queries. \nBecause we have 4 collection nodes: \"users\", \"posts\", \"comments\" and \"author\"\n\nIt does this by aggregating filters and reassembles data locally.\n\nFrom 2000 queries to 4 queries we experienced around 40x percent performance boost. \n\n## React Integration\nFor integration with React try out [cultofcoders:grapher-react](https://github.com/cult-of-coders/grapher-react) package\n\n","date":"2016-11-21T14:16:02.524Z","updated":"2016-11-21T14:16:02.524Z","path":"guide/query.html","_id":"citk02w0i0002fvjxoajo76l2","comments":1,"layout":"page","content":"<h2 id=\"Introduction\"><a href=\"#Introduction\" class=\"headerlink\" title=\"Introduction\"></a>Introduction</h2><p>Queries are a way to specify which data you want from the server using links as the backbone for creating the data graph.\nQueries can be reactive (using Meteor’s pub/sub system) or static (using method call) or direct if the call is done server side.</p>\n<p>Let’s configure some links, and then see how we can query them into the database.</p>\n<p>Assuming we have these collections: Authors, Comments, Posts, Groups, Category:</p>\n<ul>\n<li>Author has many posts.</li>\n<li>Author can belong in many groups.</li>\n<li>Posts has many comments.</li>\n<li>Posts has one category.</li>\n<li>Comments has a single author.</li>\n</ul>\n<h3 id=\"Don’t-panic\"><a href=\"#Don’t-panic\" class=\"headerlink\" title=\"Don’t panic!\"></a>Don’t panic!</h3><p>We’ll start defining our links, if something stops making sense. Review the <a href=\"/guide/links.html\">Collection Links</a> documentation again.</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div><div class=\"line\">20</div><div class=\"line\">21</div><div class=\"line\">22</div><div class=\"line\">23</div><div class=\"line\">24</div><div class=\"line\">25</div><div class=\"line\">26</div><div class=\"line\">27</div><div class=\"line\">28</div><div class=\"line\">29</div><div class=\"line\">30</div><div class=\"line\">31</div><div class=\"line\">32</div><div class=\"line\">33</div><div class=\"line\">34</div><div class=\"line\">35</div><div class=\"line\">36</div><div class=\"line\">37</div><div class=\"line\">38</div><div class=\"line\">39</div><div class=\"line\">40</div><div class=\"line\">41</div><div class=\"line\">42</div><div class=\"line\">43</div><div class=\"line\">44</div><div class=\"line\">45</div><div class=\"line\">46</div><div class=\"line\">47</div><div class=\"line\">48</div><div class=\"line\">49</div><div class=\"line\">50</div><div class=\"line\">51</div><div class=\"line\">52</div><div class=\"line\">53</div><div class=\"line\">54</div><div class=\"line\">55</div><div class=\"line\">56</div><div class=\"line\">57</div><div class=\"line\">58</div><div class=\"line\">59</div><div class=\"line\">60</div><div class=\"line\">61</div><div class=\"line\">62</div><div class=\"line\">63</div></pre></td><td class=\"code\"><pre><div class=\"line\">Authors.addLinks({</div><div class=\"line\"> <span class=\"attr\">groups</span>: {</div><div class=\"line\"> <span class=\"attr\">collection</span>: Groups,</div><div class=\"line\"> <span class=\"attr\">field</span>: <span class=\"string\">'groupIds'</span>,</div><div class=\"line\"> <span class=\"attr\">type</span>: <span class=\"string\">'many'</span></div><div class=\"line\"> },</div><div class=\"line\"> <span class=\"attr\">posts</span>: {</div><div class=\"line\"> <span class=\"attr\">collection</span>: Posts,</div><div class=\"line\"> <span class=\"attr\">inversedBy</span>: <span class=\"string\">'author'</span></div><div class=\"line\"> },</div><div class=\"line\"> <span class=\"comment\">// Resolver links only work on server-side or with non-reactive queries</span></div><div class=\"line\"> likesOnFacebook: {</div><div class=\"line\"> <span class=\"comment\">// in this case resolver will receive: object, filters, options, userId</span></div><div class=\"line\"> <span class=\"comment\">// since resolver is run server side, the author will be the full object with all the fields.</span></div><div class=\"line\"> resolve(author) {</div><div class=\"line\"> <span class=\"comment\">// do a sync call to retrieve the likes on facebook using author object.</span></div><div class=\"line\"> <span class=\"keyword\">return</span> count;</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\">});</div><div class=\"line\"></div><div class=\"line\">Posts.addLinks({</div><div class=\"line\"> <span class=\"attr\">author</span>: {</div><div class=\"line\"> <span class=\"attr\">collection</span>: Authors,</div><div class=\"line\"> <span class=\"attr\">type</span>: <span class=\"string\">'one'</span>,</div><div class=\"line\"> <span class=\"attr\">field</span>: <span class=\"string\">'authorId'</span></div><div class=\"line\"> },</div><div class=\"line\"> <span class=\"comment\">// it can have a lot of comments, so it's safer if we store the link in Comments collection</span></div><div class=\"line\"> comments: { </div><div class=\"line\"> <span class=\"attr\">collection</span>: Comments,</div><div class=\"line\"> <span class=\"attr\">inversedBy</span>: <span class=\"string\">'post'</span></div><div class=\"line\"> },</div><div class=\"line\"> <span class=\"attr\">category</span>: {</div><div class=\"line\"> <span class=\"attr\">collection</span>: Categories,</div><div class=\"line\"> <span class=\"attr\">type</span>: <span class=\"string\">'many'</span>,</div><div class=\"line\"> <span class=\"attr\">field</span>: <span class=\"string\">'categoryIds'</span></div><div class=\"line\"> }</div><div class=\"line\">});</div><div class=\"line\"></div><div class=\"line\">Comments.addLinks({</div><div class=\"line\"> <span class=\"attr\">author</span>: {</div><div class=\"line\"> <span class=\"attr\">collection</span>: Authors,</div><div class=\"line\"> <span class=\"attr\">field</span>: <span class=\"string\">'authorId'</span></div><div class=\"line\"> },</div><div class=\"line\"> <span class=\"attr\">post</span>: {</div><div class=\"line\"> <span class=\"attr\">collection</span>: Posts,</div><div class=\"line\"> <span class=\"attr\">field</span>: <span class=\"string\">'postId'</span></div><div class=\"line\"> }</div><div class=\"line\">});</div><div class=\"line\"></div><div class=\"line\">Category.addLinks({</div><div class=\"line\"> <span class=\"attr\">author</span>: {</div><div class=\"line\"> <span class=\"attr\">collection</span>: Authors,</div><div class=\"line\"> <span class=\"attr\">inversedBy</span>: <span class=\"string\">'category'</span>,</div><div class=\"line\"> }</div><div class=\"line\">});</div><div class=\"line\"></div><div class=\"line\">Groups.addLinks({</div><div class=\"line\"> <span class=\"attr\">authors</span>: {</div><div class=\"line\"> <span class=\"attr\">collection</span>: Authors,</div><div class=\"line\"> <span class=\"attr\">inversedBy</span>: <span class=\"string\">'groups'</span></div><div class=\"line\"> }</div><div class=\"line\">});</div></pre></td></tr></table></figure>\n<p>Perfect. Now that we defined our relationships we can query our database.\nAssuming we exposed “Posts” server-side, we can fetch the query client-side.</p>\n<blockquote class=\"pullquote warning\"><p>Notes:</p>\n<ul>\n<li>Use {} to specify a link, and 1 for a field.</li>\n<li>“_id” will always be fetched</li>\n<li>You must always specify the fields you need, otherwise it will only fetch _id</li>\n</ul>\n</blockquote>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div><div class=\"line\">20</div><div class=\"line\">21</div><div class=\"line\">22</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">const</span> query = Posts.createQuery({</div><div class=\"line\"> <span class=\"attr\">title</span>: <span class=\"number\">1</span>,</div><div class=\"line\"> <span class=\"comment\">// if there are no custom fields specified, it will retrieve all fields.</span></div><div class=\"line\"> author: {</div><div class=\"line\"> <span class=\"comment\">// if you have a nested object, (no link named profile) it will not try to fetch the link, but rather give you only the fields you need.</span></div><div class=\"line\"> profile: {</div><div class=\"line\"> <span class=\"attr\">firstname</span>: <span class=\"number\">1</span></div><div class=\"line\"> lastname: <span class=\"number\">1</span></div><div class=\"line\"> },</div><div class=\"line\"> <span class=\"attr\">likesOnFacebook</span>: <span class=\"number\">1</span></div><div class=\"line\"> } </div><div class=\"line\"> comments: {</div><div class=\"line\"> <span class=\"attr\">text</span>: <span class=\"number\">1</span>,</div><div class=\"line\"> <span class=\"comment\">// if you don't specify any local fields for the author, only \"_id\" field will be fetched</span></div><div class=\"line\"> <span class=\"comment\">// this will enforce the use of query and retrieve only the data you need.</span></div><div class=\"line\"> author: {</div><div class=\"line\"> <span class=\"attr\">groups</span>: {</div><div class=\"line\"> <span class=\"attr\">name</span>: <span class=\"number\">1</span></div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\">});</div></pre></td></tr></table></figure>\n<p>Now that we have created our query, we have two options of fetching the data.</p>\n<h2 id=\"Static-Queries\"><a href=\"#Static-Queries\" class=\"headerlink\" title=\"Static Queries\"></a>Static Queries</h2><p>Static methods receive their data using a method call to the exposure.</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div><div class=\"line\">20</div><div class=\"line\">21</div><div class=\"line\">22</div><div class=\"line\">23</div><div class=\"line\">24</div><div class=\"line\">25</div><div class=\"line\">26</div><div class=\"line\">27</div><div class=\"line\">28</div><div class=\"line\">29</div><div class=\"line\">30</div><div class=\"line\">31</div></pre></td><td class=\"code\"><pre><div class=\"line\">query.fetch(<span class=\"function\">(<span class=\"params\">error, response</span>) =></span> {</div><div class=\"line\"> <span class=\"comment\">// if no error occured, the response will look something like this</span></div><div class=\"line\"> [</div><div class=\"line\"> {</div><div class=\"line\"> <span class=\"attr\">_id</span>: <span class=\"string\">'XXXXXXXXXXXXXXX'</span>,</div><div class=\"line\"> <span class=\"attr\">title</span>: <span class=\"string\">'Hello World!'</span>,</div><div class=\"line\"> <span class=\"attr\">author</span>: {</div><div class=\"line\"> <span class=\"attr\">profile</span>: {</div><div class=\"line\"> <span class=\"attr\">firstname</span>: <span class=\"string\">'John'</span>,</div><div class=\"line\"> <span class=\"attr\">lastname</span>: <span class=\"string\">'Smith'</span></div><div class=\"line\"> }</div><div class=\"line\"> likesOnFacebook: <span class=\"number\">200</span></div><div class=\"line\"> },</div><div class=\"line\"> <span class=\"attr\">comments</span>: [</div><div class=\"line\"> {</div><div class=\"line\"> <span class=\"attr\">text</span>: <span class=\"string\">'Nice Post'</span>,</div><div class=\"line\"> <span class=\"attr\">author</span>: {</div><div class=\"line\"> <span class=\"attr\">_id</span>: <span class=\"string\">'XXXXXXXXXXXXX'</span></div><div class=\"line\"> },</div><div class=\"line\"> <span class=\"attr\">groups</span>: [</div><div class=\"line\"> {</div><div class=\"line\"> <span class=\"attr\">_id</span>: <span class=\"string\">'XXXXXXXXXXX'</span>,</div><div class=\"line\"> <span class=\"attr\">name</span>: <span class=\"string\">'Group 1'</span></div><div class=\"line\"> }</div><div class=\"line\"> ]</div><div class=\"line\"> }</div><div class=\"line\"> ]</div><div class=\"line\"> },</div><div class=\"line\"> ...</div><div class=\"line\"> ]</div><div class=\"line\">});</div></pre></td></tr></table></figure>\n<h2 id=\"Reactive-Queries\"><a href=\"#Reactive-Queries\" class=\"headerlink\" title=\"Reactive Queries\"></a>Reactive Queries</h2><figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">const</span> subsHandle = query.subscribe();</div><div class=\"line\"><span class=\"keyword\">const</span> data = query.fetch();</div><div class=\"line\"></div><div class=\"line\">query.unsubscribe();</div><div class=\"line\">query.fetch(); <span class=\"comment\">// now it will fail because you did not provide a callback, because when you unsubscribe, we delete the subscriptionHandle</span></div></pre></td></tr></table></figure>\n<blockquote class=\"pullquote warning\"><p>Important! If you previously subscribed, fetching will be done client side using client-side collections,\nif you did not previously subscribe, you need to provide a callback because data will be fetched via a method call.</p>\n</blockquote>\n<p>If you don’t want to use .fetch() you can also use the collections as you previously used to:</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div></pre></td><td class=\"code\"><pre><div class=\"line\">Posts.find().fetch()</div><div class=\"line\">Comments.find({<span class=\"attr\">postId</span>: <span class=\"string\">'XXXXXX'</span>}).fetch()</div></pre></td></tr></table></figure>\n<h2 id=\"Creating-a-query-without-the-collection-object\"><a href=\"#Creating-a-query-without-the-collection-object\" class=\"headerlink\" title=\"Creating a query without the collection object\"></a>Creating a query without the collection object</h2><figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">import</span> { createQuery } <span class=\"keyword\">from</span> <span class=\"string\">'meteor/cultofcoders:grapher'</span>;</div><div class=\"line\"></div><div class=\"line\">createQuery({</div><div class=\"line\"> <span class=\"attr\">posts</span>: {</div><div class=\"line\"> <span class=\"attr\">comments</span>: {</div><div class=\"line\"> <span class=\"attr\">text</span>: <span class=\"number\">1</span></div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\">});</div></pre></td></tr></table></figure>\n<p><em>posts</em> is the name of the collection, specified as the first parameter in the <em>Mongo.Collection</em> constructor.</p>\n<h2 id=\"filters-and-options\"><a href=\"#filters-and-options\" class=\"headerlink\" title=\"$filters and $options\"></a>$filters and $options</h2><p>At any given collection node in your query you can specify different filtering techniques.</p>\n<p>Available $filters: <a href=\"http://docs.meteor.com/api/collections.html#selectors\" target=\"_blank\" rel=\"external\">http://docs.meteor.com/api/collections.html#selectors</a></p>\n<p>Available $options: <em>sort</em>, <em>skip</em> and <em>limit</em> \nRead more: <a href=\"http://docs.meteor.com/api/collections.html#Mongo-Collection-find\" target=\"_blank\" rel=\"external\">http://docs.meteor.com/api/collections.html#Mongo-Collection-find</a></p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">const</span> query = Posts.createQuery({</div><div class=\"line\"> <span class=\"attr\">$filters</span>: {<span class=\"attr\">isApproved</span>: <span class=\"literal\">true</span>} <span class=\"comment\">// this will find only posts that have isApproved: true</span></div><div class=\"line\"> $options: {</div><div class=\"line\"> <span class=\"attr\">limit</span>: <span class=\"number\">100</span></div><div class=\"line\"> }</div><div class=\"line\"> title: <span class=\"number\">1</span></div><div class=\"line\"> comments: {</div><div class=\"line\"> <span class=\"attr\">$filters</span>: { <span class=\"comment\">// this will only search the comments that have isNotSpam: true</span></div><div class=\"line\"> isNotSpam: <span class=\"literal\">true</span></div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\">});</div></pre></td></tr></table></figure>\n<h2 id=\"Parameters\"><a href=\"#Parameters\" class=\"headerlink\" title=\"Parameters\"></a>Parameters</h2><p>You can pass params to your query, they will be available in every $filter() function.\nUsing $filter() gives you enough control to filters and options. So $filters and $options may be omitted.</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">const</span> query = Posts.createQuery({</div><div class=\"line\"> $filter({filters, options, params}) {</div><div class=\"line\"> filters.isApproved = params.isApproved</div><div class=\"line\"> }</div><div class=\"line\"> title: <span class=\"number\">1</span></div><div class=\"line\"> comments: {</div><div class=\"line\"> $filter({filters, options, params}) {</div><div class=\"line\"> <span class=\"keyword\">if</span> (params.allowSpamComments) {</div><div class=\"line\"> filters.isNotSpam = <span class=\"literal\">undefined</span>; <span class=\"comment\">// $filter() overrides $filters and $options</span></div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\"> $filters: { <span class=\"comment\">// this will only search the comments that have isNotSpam: true</span></div><div class=\"line\"> isNotSpam: <span class=\"literal\">true</span></div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\">}, {</div><div class=\"line\"> <span class=\"attr\">isApproved</span>: <span class=\"literal\">true</span>,</div><div class=\"line\"> <span class=\"attr\">allowSpamComments</span>: <span class=\"literal\">true</span></div><div class=\"line\">});</div></pre></td></tr></table></figure>\n<p>Control parameters however you wish:\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div></pre></td><td class=\"code\"><pre><div class=\"line\">query.setParams({</div><div class=\"line\"> <span class=\"attr\">allowSpamComments</span>: <span class=\"literal\">false</span></div><div class=\"line\">});</div></pre></td></tr></table></figure></p>\n<p>Using it with <em>React</em> and <em>react-meteor-data</em> package:</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">import</span> { createContainer } <span class=\"keyword\">from</span> <span class=\"string\">'meteor/react-meteor-data'</span>;</div><div class=\"line\"><span class=\"keyword\">import</span> query <span class=\"keyword\">from</span> <span class=\"string\">'./listPostsQuery.js'</span>;</div><div class=\"line\"></div><div class=\"line\"><span class=\"keyword\">const</span> localQuery = query.clone();</div><div class=\"line\"></div><div class=\"line\"><span class=\"keyword\">export</span> <span class=\"keyword\">default</span> createContainer(<span class=\"function\"><span class=\"params\">()</span> =></span> {</div><div class=\"line\"> <span class=\"keyword\">const</span> handle = localQuery.subscribe();</div><div class=\"line\"> <span class=\"keyword\">const</span> posts = localQuery.fetch();</div><div class=\"line\"> </div><div class=\"line\"> <span class=\"keyword\">return</span> {</div><div class=\"line\"> <span class=\"attr\">isReady</span>: handle.isReady(),</div><div class=\"line\"> <span class=\"attr\">posts</span>: posts</div><div class=\"line\"> }</div><div class=\"line\">}, PostList);</div></pre></td></tr></table></figure>\n<blockquote class=\"pullquote warning\"><p>We use .clone() method to avoid making changes on the actual query (like setParams). \nYou could do is export a factory that creates your query on the fly, however, for simplicity,\nwe created a .clone() method, that clones the query and it is completely isolated.</p>\n</blockquote>\n<blockquote class=\"pullquote warning\"><p>When you have metadata links. A $metadata object will be stored to the children referncing the $metadata from the parent.</p>\n</blockquote>\n<h2 id=\"Reducers\"><a href=\"#Reducers\" class=\"headerlink\" title=\"Reducers\"></a>Reducers</h2><h3 id=\"Basic\"><a href=\"#Basic\" class=\"headerlink\" title=\"Basic\"></a>Basic</h3><p>Reducers are a way of combining the data from your graph request. Best to show an example:\n<figure class=\"highlight dts\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">// setting up</span></div><div class=\"line\">Users.addReducers({</div><div class=\"line\"><span class=\"symbol\"> fullName:</span> { <span class=\"comment\">// the name of how you want to request it</span></div><div class=\"line\"><span class=\"symbol\"> body:</span> { <span class=\"comment\">// the dependency, what info it needs to be able to reduce</span></div><div class=\"line\"><span class=\"symbol\"> profile:</span> {</div><div class=\"line\"><span class=\"symbol\"> firstName:</span> <span class=\"number\">1</span>,</div><div class=\"line\"><span class=\"symbol\"> lastName:</span> <span class=\"number\">1</span></div><div class=\"line\"> }</div><div class=\"line\"> },</div><div class=\"line\"> reduce(object) { <span class=\"comment\">// a pure function that returns the data</span></div><div class=\"line\"> return object.profile.firstName + <span class=\"string\">' '</span> + object.profile.lastName;</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\">})</div></pre></td></tr></table></figure></p>\n<figure class=\"highlight less\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">// usage</span></div><div class=\"line\"><span class=\"selector-tag\">createQuery</span>({</div><div class=\"line\"> <span class=\"attribute\">users</span>: {</div><div class=\"line\"> <span class=\"attribute\">fullName</span>: <span class=\"number\">1</span></div><div class=\"line\"> }</div><div class=\"line\">})</div></pre></td></tr></table></figure>\n<h3 id=\"Reducers-can-make-use-of-links\"><a href=\"#Reducers-can-make-use-of-links\" class=\"headerlink\" title=\"Reducers can make use of links\"></a>Reducers can make use of links</h3><p>Easily grab the data from your links, if you want to reduce it.</p>\n<figure class=\"highlight less\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"selector-tag\">Users</span><span class=\"selector-class\">.addReducers</span>({</div><div class=\"line\"> <span class=\"attribute\">groups</span>: { <span class=\"comment\">// the name of how you want to request it</span></div><div class=\"line\"> <span class=\"attribute\">body</span>: {</div><div class=\"line\"> <span class=\"attribute\">groups</span>: { <span class=\"attribute\">name</span>: <span class=\"number\">1</span> } <span class=\"comment\">// assuming you have a link called groups</span></div><div class=\"line\"> },</div><div class=\"line\"> reduce(object) { <span class=\"comment\">// a pure function that returns the data</span></div><div class=\"line\"> <span class=\"selector-tag\">return</span> <span class=\"selector-tag\">object</span><span class=\"selector-class\">.groups</span><span class=\"selector-class\">.map</span>(group => group.name)<span class=\"selector-class\">.join</span>(<span class=\"string\">','</span>)</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\">})</div></pre></td></tr></table></figure>\n<h3 id=\"Reducers-can-use-other-reducers\"><a href=\"#Reducers-can-use-other-reducers\" class=\"headerlink\" title=\"Reducers can use other reducers\"></a>Reducers can use other reducers</h3><figure class=\"highlight less\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">// setting up</span></div><div class=\"line\"><span class=\"selector-tag\">Users</span><span class=\"selector-class\">.addReducers</span>({</div><div class=\"line\"> <span class=\"attribute\">fullNameWithRoles</span>: { <span class=\"comment\">// the name of how you want to request it</span></div><div class=\"line\"> <span class=\"attribute\">body</span>: { <span class=\"comment\">// the dependency, what info it needs to be able to reduce</span></div><div class=\"line\"> <span class=\"attribute\">fullName</span>: <span class=\"number\">1</span>,</div><div class=\"line\"> <span class=\"attribute\">roles</span>: <span class=\"number\">1</span></div><div class=\"line\"> },</div><div class=\"line\"> <span class=\"selector-tag\">reduce</span>(object) { <span class=\"comment\">// a pure function that returns the data</span></div><div class=\"line\"> <span class=\"selector-tag\">return</span> <span class=\"selector-tag\">object</span><span class=\"selector-class\">.fullName</span> + <span class=\"selector-tag\">object</span><span class=\"selector-class\">.roles</span><span class=\"selector-class\">.join</span>(<span class=\"string\">','</span>);</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\">})</div></pre></td></tr></table></figure>\n<blockquote class=\"pullquote warning\"><p>If you do not explicitly request the fields that the reducer needs, they will not be present in your response.</p>\n</blockquote>\n<h2 id=\"Security-and-Performance\"><a href=\"#Security-and-Performance\" class=\"headerlink\" title=\"Security and Performance\"></a>Security and Performance</h2><p>By default the options “disableOplog”, “pollingIntervalMs”, “pollingThrottleMs” are not available on the client.\nYou can control them in the firewall of your exposure.</p>\n<p>Grapher is very performant. To understand what we’re talking about let’s take this example:\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div></pre></td><td class=\"code\"><pre><div class=\"line\">{</div><div class=\"line\"> <span class=\"attr\">users</span>: {</div><div class=\"line\"> <span class=\"attr\">posts</span>: {</div><div class=\"line\"> <span class=\"attr\">comments</span>: {</div><div class=\"line\"> <span class=\"attr\">author</span>: {}</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\">}</div></pre></td></tr></table></figure></p>\n<p>For a query like this, if we would’ve first received the users, then the posts for each user, then the comments for each post, then the author for each comments.\nWe would’ve blasted MongoDB with a lot of queries, and the number of queries increases exponentially. It can easily be around ~2000 for a simple query.</p>\n<p>However, using the <em>Hypernova</em> module, an innovative approach, the query above is executed with only 4 queries. \nBecause we have 4 collection nodes: “users”, “posts”, “comments” and “author”</p>\n<p>It does this by aggregating filters and reassembles data locally.</p>\n<p>From 2000 queries to 4 queries we experienced around 40x percent performance boost. </p>\n<h2 id=\"React-Integration\"><a href=\"#React-Integration\" class=\"headerlink\" title=\"React Integration\"></a>React Integration</h2><p>For integration with React try out <a href=\"https://github.com/cult-of-coders/grapher-react\" target=\"_blank\" rel=\"external\">cultofcoders:grapher-react</a> package</p>\n","excerpt":"","more":"<h2 id=\"Introduction\"><a href=\"#Introduction\" class=\"headerlink\" title=\"Introduction\"></a>Introduction</h2><p>Queries are a way to specify which data you want from the server using links as the backbone for creating the data graph.\nQueries can be reactive (using Meteor’s pub/sub system) or static (using method call) or direct if the call is done server side.</p>\n<p>Let’s configure some links, and then see how we can query them into the database.</p>\n<p>Assuming we have these collections: Authors, Comments, Posts, Groups, Category:</p>\n<ul>\n<li>Author has many posts.</li>\n<li>Author can belong in many groups.</li>\n<li>Posts has many comments.</li>\n<li>Posts has one category.</li>\n<li>Comments has a single author.</li>\n</ul>\n<h3 id=\"Don’t-panic\"><a href=\"#Don’t-panic\" class=\"headerlink\" title=\"Don’t panic!\"></a>Don’t panic!</h3><p>We’ll start defining our links, if something stops making sense. Review the <a href=\"/guide/links.html\">Collection Links</a> documentation again.</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div><div class=\"line\">20</div><div class=\"line\">21</div><div class=\"line\">22</div><div class=\"line\">23</div><div class=\"line\">24</div><div class=\"line\">25</div><div class=\"line\">26</div><div class=\"line\">27</div><div class=\"line\">28</div><div class=\"line\">29</div><div class=\"line\">30</div><div class=\"line\">31</div><div class=\"line\">32</div><div class=\"line\">33</div><div class=\"line\">34</div><div class=\"line\">35</div><div class=\"line\">36</div><div class=\"line\">37</div><div class=\"line\">38</div><div class=\"line\">39</div><div class=\"line\">40</div><div class=\"line\">41</div><div class=\"line\">42</div><div class=\"line\">43</div><div class=\"line\">44</div><div class=\"line\">45</div><div class=\"line\">46</div><div class=\"line\">47</div><div class=\"line\">48</div><div class=\"line\">49</div><div class=\"line\">50</div><div class=\"line\">51</div><div class=\"line\">52</div><div class=\"line\">53</div><div class=\"line\">54</div><div class=\"line\">55</div><div class=\"line\">56</div><div class=\"line\">57</div><div class=\"line\">58</div><div class=\"line\">59</div><div class=\"line\">60</div><div class=\"line\">61</div><div class=\"line\">62</div><div class=\"line\">63</div></pre></td><td class=\"code\"><pre><div class=\"line\">Authors.addLinks({</div><div class=\"line\"> <span class=\"attr\">groups</span>: {</div><div class=\"line\"> <span class=\"attr\">collection</span>: Groups,</div><div class=\"line\"> <span class=\"attr\">field</span>: <span class=\"string\">'groupIds'</span>,</div><div class=\"line\"> <span class=\"attr\">type</span>: <span class=\"string\">'many'</span></div><div class=\"line\"> },</div><div class=\"line\"> <span class=\"attr\">posts</span>: {</div><div class=\"line\"> <span class=\"attr\">collection</span>: Posts,</div><div class=\"line\"> <span class=\"attr\">inversedBy</span>: <span class=\"string\">'author'</span></div><div class=\"line\"> },</div><div class=\"line\"> <span class=\"comment\">// Resolver links only work on server-side or with non-reactive queries</span></div><div class=\"line\"> likesOnFacebook: {</div><div class=\"line\"> <span class=\"comment\">// in this case resolver will receive: object, filters, options, userId</span></div><div class=\"line\"> <span class=\"comment\">// since resolver is run server side, the author will be the full object with all the fields.</span></div><div class=\"line\"> resolve(author) {</div><div class=\"line\"> <span class=\"comment\">// do a sync call to retrieve the likes on facebook using author object.</span></div><div class=\"line\"> <span class=\"keyword\">return</span> count;</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\">});</div><div class=\"line\"></div><div class=\"line\">Posts.addLinks({</div><div class=\"line\"> <span class=\"attr\">author</span>: {</div><div class=\"line\"> <span class=\"attr\">collection</span>: Authors,</div><div class=\"line\"> <span class=\"attr\">type</span>: <span class=\"string\">'one'</span>,</div><div class=\"line\"> <span class=\"attr\">field</span>: <span class=\"string\">'authorId'</span></div><div class=\"line\"> },</div><div class=\"line\"> <span class=\"comment\">// it can have a lot of comments, so it's safer if we store the link in Comments collection</span></div><div class=\"line\"> comments: { </div><div class=\"line\"> <span class=\"attr\">collection</span>: Comments,</div><div class=\"line\"> <span class=\"attr\">inversedBy</span>: <span class=\"string\">'post'</span></div><div class=\"line\"> },</div><div class=\"line\"> <span class=\"attr\">category</span>: {</div><div class=\"line\"> <span class=\"attr\">collection</span>: Categories,</div><div class=\"line\"> <span class=\"attr\">type</span>: <span class=\"string\">'many'</span>,</div><div class=\"line\"> <span class=\"attr\">field</span>: <span class=\"string\">'categoryIds'</span></div><div class=\"line\"> }</div><div class=\"line\">});</div><div class=\"line\"></div><div class=\"line\">Comments.addLinks({</div><div class=\"line\"> <span class=\"attr\">author</span>: {</div><div class=\"line\"> <span class=\"attr\">collection</span>: Authors,</div><div class=\"line\"> <span class=\"attr\">field</span>: <span class=\"string\">'authorId'</span></div><div class=\"line\"> },</div><div class=\"line\"> <span class=\"attr\">post</span>: {</div><div class=\"line\"> <span class=\"attr\">collection</span>: Posts,</div><div class=\"line\"> <span class=\"attr\">field</span>: <span class=\"string\">'postId'</span></div><div class=\"line\"> }</div><div class=\"line\">});</div><div class=\"line\"></div><div class=\"line\">Category.addLinks({</div><div class=\"line\"> <span class=\"attr\">author</span>: {</div><div class=\"line\"> <span class=\"attr\">collection</span>: Authors,</div><div class=\"line\"> <span class=\"attr\">inversedBy</span>: <span class=\"string\">'category'</span>,</div><div class=\"line\"> }</div><div class=\"line\">});</div><div class=\"line\"></div><div class=\"line\">Groups.addLinks({</div><div class=\"line\"> <span class=\"attr\">authors</span>: {</div><div class=\"line\"> <span class=\"attr\">collection</span>: Authors,</div><div class=\"line\"> <span class=\"attr\">inversedBy</span>: <span class=\"string\">'groups'</span></div><div class=\"line\"> }</div><div class=\"line\">});</div></pre></td></tr></table></figure>\n<p>Perfect. Now that we defined our relationships we can query our database.\nAssuming we exposed “Posts” server-side, we can fetch the query client-side.</p>\n<blockquote class=\"pullquote warning\"><p>Notes:</p>\n<ul>\n<li>Use {} to specify a link, and 1 for a field.</li>\n<li>“_id” will always be fetched</li>\n<li>You must always specify the fields you need, otherwise it will only fetch _id</li>\n</ul>\n</blockquote>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div><div class=\"line\">20</div><div class=\"line\">21</div><div class=\"line\">22</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">const</span> query = Posts.createQuery({</div><div class=\"line\"> <span class=\"attr\">title</span>: <span class=\"number\">1</span>,</div><div class=\"line\"> <span class=\"comment\">// if there are no custom fields specified, it will retrieve all fields.</span></div><div class=\"line\"> author: {</div><div class=\"line\"> <span class=\"comment\">// if you have a nested object, (no link named profile) it will not try to fetch the link, but rather give you only the fields you need.</span></div><div class=\"line\"> profile: {</div><div class=\"line\"> <span class=\"attr\">firstname</span>: <span class=\"number\">1</span></div><div class=\"line\"> lastname: <span class=\"number\">1</span></div><div class=\"line\"> },</div><div class=\"line\"> <span class=\"attr\">likesOnFacebook</span>: <span class=\"number\">1</span></div><div class=\"line\"> } </div><div class=\"line\"> comments: {</div><div class=\"line\"> <span class=\"attr\">text</span>: <span class=\"number\">1</span>,</div><div class=\"line\"> <span class=\"comment\">// if you don't specify any local fields for the author, only \"_id\" field will be fetched</span></div><div class=\"line\"> <span class=\"comment\">// this will enforce the use of query and retrieve only the data you need.</span></div><div class=\"line\"> author: {</div><div class=\"line\"> <span class=\"attr\">groups</span>: {</div><div class=\"line\"> <span class=\"attr\">name</span>: <span class=\"number\">1</span></div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\">});</div></pre></td></tr></table></figure>\n<p>Now that we have created our query, we have two options of fetching the data.</p>\n<h2 id=\"Static-Queries\"><a href=\"#Static-Queries\" class=\"headerlink\" title=\"Static Queries\"></a>Static Queries</h2><p>Static methods receive their data using a method call to the exposure.</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div><div class=\"line\">20</div><div class=\"line\">21</div><div class=\"line\">22</div><div class=\"line\">23</div><div class=\"line\">24</div><div class=\"line\">25</div><div class=\"line\">26</div><div class=\"line\">27</div><div class=\"line\">28</div><div class=\"line\">29</div><div class=\"line\">30</div><div class=\"line\">31</div></pre></td><td class=\"code\"><pre><div class=\"line\">query.fetch(<span class=\"function\">(<span class=\"params\">error, response</span>) =></span> {</div><div class=\"line\"> <span class=\"comment\">// if no error occured, the response will look something like this</span></div><div class=\"line\"> [</div><div class=\"line\"> {</div><div class=\"line\"> <span class=\"attr\">_id</span>: <span class=\"string\">'XXXXXXXXXXXXXXX'</span>,</div><div class=\"line\"> <span class=\"attr\">title</span>: <span class=\"string\">'Hello World!'</span>,</div><div class=\"line\"> <span class=\"attr\">author</span>: {</div><div class=\"line\"> <span class=\"attr\">profile</span>: {</div><div class=\"line\"> <span class=\"attr\">firstname</span>: <span class=\"string\">'John'</span>,</div><div class=\"line\"> <span class=\"attr\">lastname</span>: <span class=\"string\">'Smith'</span></div><div class=\"line\"> }</div><div class=\"line\"> likesOnFacebook: <span class=\"number\">200</span></div><div class=\"line\"> },</div><div class=\"line\"> <span class=\"attr\">comments</span>: [</div><div class=\"line\"> {</div><div class=\"line\"> <span class=\"attr\">text</span>: <span class=\"string\">'Nice Post'</span>,</div><div class=\"line\"> <span class=\"attr\">author</span>: {</div><div class=\"line\"> <span class=\"attr\">_id</span>: <span class=\"string\">'XXXXXXXXXXXXX'</span></div><div class=\"line\"> },</div><div class=\"line\"> <span class=\"attr\">groups</span>: [</div><div class=\"line\"> {</div><div class=\"line\"> <span class=\"attr\">_id</span>: <span class=\"string\">'XXXXXXXXXXX'</span>,</div><div class=\"line\"> <span class=\"attr\">name</span>: <span class=\"string\">'Group 1'</span></div><div class=\"line\"> }</div><div class=\"line\"> ]</div><div class=\"line\"> }</div><div class=\"line\"> ]</div><div class=\"line\"> },</div><div class=\"line\"> ...</div><div class=\"line\"> ]</div><div class=\"line\">});</div></pre></td></tr></table></figure>\n<h2 id=\"Reactive-Queries\"><a href=\"#Reactive-Queries\" class=\"headerlink\" title=\"Reactive Queries\"></a>Reactive Queries</h2><figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">const</span> subsHandle = query.subscribe();</div><div class=\"line\"><span class=\"keyword\">const</span> data = query.fetch();</div><div class=\"line\"></div><div class=\"line\">query.unsubscribe();</div><div class=\"line\">query.fetch(); <span class=\"comment\">// now it will fail because you did not provide a callback, because when you unsubscribe, we delete the subscriptionHandle</span></div></pre></td></tr></table></figure>\n<blockquote class=\"pullquote warning\"><p>Important! If you previously subscribed, fetching will be done client side using client-side collections,\nif you did not previously subscribe, you need to provide a callback because data will be fetched via a method call.</p>\n</blockquote>\n<p>If you don’t want to use .fetch() you can also use the collections as you previously used to:</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div></pre></td><td class=\"code\"><pre><div class=\"line\">Posts.find().fetch()</div><div class=\"line\">Comments.find({<span class=\"attr\">postId</span>: <span class=\"string\">'XXXXXX'</span>}).fetch()</div></pre></td></tr></table></figure>\n<h2 id=\"Creating-a-query-without-the-collection-object\"><a href=\"#Creating-a-query-without-the-collection-object\" class=\"headerlink\" title=\"Creating a query without the collection object\"></a>Creating a query without the collection object</h2><figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">import</span> { createQuery } <span class=\"keyword\">from</span> <span class=\"string\">'meteor/cultofcoders:grapher'</span>;</div><div class=\"line\"></div><div class=\"line\">createQuery({</div><div class=\"line\"> <span class=\"attr\">posts</span>: {</div><div class=\"line\"> <span class=\"attr\">comments</span>: {</div><div class=\"line\"> <span class=\"attr\">text</span>: <span class=\"number\">1</span></div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\">});</div></pre></td></tr></table></figure>\n<p><em>posts</em> is the name of the collection, specified as the first parameter in the <em>Mongo.Collection</em> constructor.</p>\n<h2 id=\"filters-and-options\"><a href=\"#filters-and-options\" class=\"headerlink\" title=\"$filters and $options\"></a>$filters and $options</h2><p>At any given collection node in your query you can specify different filtering techniques.</p>\n<p>Available $filters: <a href=\"http://docs.meteor.com/api/collections.html#selectors\">http://docs.meteor.com/api/collections.html#selectors</a></p>\n<p>Available $options: <em>sort</em>, <em>skip</em> and <em>limit</em> \nRead more: <a href=\"http://docs.meteor.com/api/collections.html#Mongo-Collection-find\">http://docs.meteor.com/api/collections.html#Mongo-Collection-find</a></p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">const</span> query = Posts.createQuery({</div><div class=\"line\"> <span class=\"attr\">$filters</span>: {<span class=\"attr\">isApproved</span>: <span class=\"literal\">true</span>} <span class=\"comment\">// this will find only posts that have isApproved: true</span></div><div class=\"line\"> $options: {</div><div class=\"line\"> <span class=\"attr\">limit</span>: <span class=\"number\">100</span></div><div class=\"line\"> }</div><div class=\"line\"> title: <span class=\"number\">1</span></div><div class=\"line\"> comments: {</div><div class=\"line\"> <span class=\"attr\">$filters</span>: { <span class=\"comment\">// this will only search the comments that have isNotSpam: true</span></div><div class=\"line\"> isNotSpam: <span class=\"literal\">true</span></div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\">});</div></pre></td></tr></table></figure>\n<h2 id=\"Parameters\"><a href=\"#Parameters\" class=\"headerlink\" title=\"Parameters\"></a>Parameters</h2><p>You can pass params to your query, they will be available in every $filter() function.\nUsing $filter() gives you enough control to filters and options. So $filters and $options may be omitted.</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">const</span> query = Posts.createQuery({</div><div class=\"line\"> $filter({filters, options, params}) {</div><div class=\"line\"> filters.isApproved = params.isApproved</div><div class=\"line\"> }</div><div class=\"line\"> title: <span class=\"number\">1</span></div><div class=\"line\"> comments: {</div><div class=\"line\"> $filter({filters, options, params}) {</div><div class=\"line\"> <span class=\"keyword\">if</span> (params.allowSpamComments) {</div><div class=\"line\"> filters.isNotSpam = <span class=\"literal\">undefined</span>; <span class=\"comment\">// $filter() overrides $filters and $options</span></div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\"> $filters: { <span class=\"comment\">// this will only search the comments that have isNotSpam: true</span></div><div class=\"line\"> isNotSpam: <span class=\"literal\">true</span></div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\">}, {</div><div class=\"line\"> <span class=\"attr\">isApproved</span>: <span class=\"literal\">true</span>,</div><div class=\"line\"> <span class=\"attr\">allowSpamComments</span>: <span class=\"literal\">true</span></div><div class=\"line\">});</div></pre></td></tr></table></figure>\n<p>Control parameters however you wish:\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div></pre></td><td class=\"code\"><pre><div class=\"line\">query.setParams({</div><div class=\"line\"> <span class=\"attr\">allowSpamComments</span>: <span class=\"literal\">false</span></div><div class=\"line\">});</div></pre></td></tr></table></figure></p>\n<p>Using it with <em>React</em> and <em>react-meteor-data</em> package:</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">import</span> { createContainer } <span class=\"keyword\">from</span> <span class=\"string\">'meteor/react-meteor-data'</span>;</div><div class=\"line\"><span class=\"keyword\">import</span> query <span class=\"keyword\">from</span> <span class=\"string\">'./listPostsQuery.js'</span>;</div><div class=\"line\"></div><div class=\"line\"><span class=\"keyword\">const</span> localQuery = query.clone();</div><div class=\"line\"></div><div class=\"line\"><span class=\"keyword\">export</span> <span class=\"keyword\">default</span> createContainer(<span class=\"function\"><span class=\"params\">()</span> =></span> {</div><div class=\"line\"> <span class=\"keyword\">const</span> handle = localQuery.subscribe();</div><div class=\"line\"> <span class=\"keyword\">const</span> posts = localQuery.fetch();</div><div class=\"line\"> </div><div class=\"line\"> <span class=\"keyword\">return</span> {</div><div class=\"line\"> <span class=\"attr\">isReady</span>: handle.isReady(),</div><div class=\"line\"> <span class=\"attr\">posts</span>: posts</div><div class=\"line\"> }</div><div class=\"line\">}, PostList);</div></pre></td></tr></table></figure>\n<blockquote class=\"pullquote warning\"><p>We use .clone() method to avoid making changes on the actual query (like setParams). \nYou could do is export a factory that creates your query on the fly, however, for simplicity,\nwe created a .clone() method, that clones the query and it is completely isolated.</p>\n</blockquote>\n<blockquote class=\"pullquote warning\"><p>When you have metadata links. A $metadata object will be stored to the children referncing the $metadata from the parent.</p>\n</blockquote>\n<h2 id=\"Reducers\"><a href=\"#Reducers\" class=\"headerlink\" title=\"Reducers\"></a>Reducers</h2><h3 id=\"Basic\"><a href=\"#Basic\" class=\"headerlink\" title=\"Basic\"></a>Basic</h3><p>Reducers are a way of combining the data from your graph request. Best to show an example:\n<figure class=\"highlight dts\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">// setting up</span></div><div class=\"line\">Users.addReducers({</div><div class=\"line\"><span class=\"symbol\"> fullName:</span> { <span class=\"comment\">// the name of how you want to request it</span></div><div class=\"line\"><span class=\"symbol\"> body:</span> { <span class=\"comment\">// the dependency, what info it needs to be able to reduce</span></div><div class=\"line\"><span class=\"symbol\"> profile:</span> {</div><div class=\"line\"><span class=\"symbol\"> firstName:</span> <span class=\"number\">1</span>,</div><div class=\"line\"><span class=\"symbol\"> lastName:</span> <span class=\"number\">1</span></div><div class=\"line\"> }</div><div class=\"line\"> },</div><div class=\"line\"> reduce(object) { <span class=\"comment\">// a pure function that returns the data</span></div><div class=\"line\"> return object.profile.firstName + <span class=\"string\">' '</span> + object.profile.lastName;</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\">})</div></pre></td></tr></table></figure></p>\n<figure class=\"highlight less\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">// usage</span></div><div class=\"line\"><span class=\"selector-tag\">createQuery</span>({</div><div class=\"line\"> <span class=\"attribute\">users</span>: {</div><div class=\"line\"> <span class=\"attribute\">fullName</span>: <span class=\"number\">1</span></div><div class=\"line\"> }</div><div class=\"line\">})</div></pre></td></tr></table></figure>\n<h3 id=\"Reducers-can-make-use-of-links\"><a href=\"#Reducers-can-make-use-of-links\" class=\"headerlink\" title=\"Reducers can make use of links\"></a>Reducers can make use of links</h3><p>Easily grab the data from your links, if you want to reduce it.</p>\n<figure class=\"highlight less\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"selector-tag\">Users</span><span class=\"selector-class\">.addReducers</span>({</div><div class=\"line\"> <span class=\"attribute\">groups</span>: { <span class=\"comment\">// the name of how you want to request it</span></div><div class=\"line\"> <span class=\"attribute\">body</span>: {</div><div class=\"line\"> <span class=\"attribute\">groups</span>: { <span class=\"attribute\">name</span>: <span class=\"number\">1</span> } <span class=\"comment\">// assuming you have a link called groups</span></div><div class=\"line\"> },</div><div class=\"line\"> reduce(object) { <span class=\"comment\">// a pure function that returns the data</span></div><div class=\"line\"> <span class=\"selector-tag\">return</span> <span class=\"selector-tag\">object</span><span class=\"selector-class\">.groups</span><span class=\"selector-class\">.map</span>(group => group.name)<span class=\"selector-class\">.join</span>(<span class=\"string\">','</span>)</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\">})</div></pre></td></tr></table></figure>\n<h3 id=\"Reducers-can-use-other-reducers\"><a href=\"#Reducers-can-use-other-reducers\" class=\"headerlink\" title=\"Reducers can use other reducers\"></a>Reducers can use other reducers</h3><figure class=\"highlight less\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">// setting up</span></div><div class=\"line\"><span class=\"selector-tag\">Users</span><span class=\"selector-class\">.addReducers</span>({</div><div class=\"line\"> <span class=\"attribute\">fullNameWithRoles</span>: { <span class=\"comment\">// the name of how you want to request it</span></div><div class=\"line\"> <span class=\"attribute\">body</span>: { <span class=\"comment\">// the dependency, what info it needs to be able to reduce</span></div><div class=\"line\"> <span class=\"attribute\">fullName</span>: <span class=\"number\">1</span>,</div><div class=\"line\"> <span class=\"attribute\">roles</span>: <span class=\"number\">1</span></div><div class=\"line\"> },</div><div class=\"line\"> <span class=\"selector-tag\">reduce</span>(object) { <span class=\"comment\">// a pure function that returns the data</span></div><div class=\"line\"> <span class=\"selector-tag\">return</span> <span class=\"selector-tag\">object</span><span class=\"selector-class\">.fullName</span> + <span class=\"selector-tag\">object</span><span class=\"selector-class\">.roles</span><span class=\"selector-class\">.join</span>(<span class=\"string\">','</span>);</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\">})</div></pre></td></tr></table></figure>\n<blockquote class=\"pullquote warning\"><p>If you do not explicitly request the fields that the reducer needs, they will not be present in your response.</p>\n</blockquote>\n<h2 id=\"Security-and-Performance\"><a href=\"#Security-and-Performance\" class=\"headerlink\" title=\"Security and Performance\"></a>Security and Performance</h2><p>By default the options “disableOplog”, “pollingIntervalMs”, “pollingThrottleMs” are not available on the client.\nYou can control them in the firewall of your exposure.</p>\n<p>Grapher is very performant. To understand what we’re talking about let’s take this example:\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div></pre></td><td class=\"code\"><pre><div class=\"line\">{</div><div class=\"line\"> <span class=\"attr\">users</span>: {</div><div class=\"line\"> <span class=\"attr\">posts</span>: {</div><div class=\"line\"> <span class=\"attr\">comments</span>: {</div><div class=\"line\"> <span class=\"attr\">author</span>: {}</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\">}</div></pre></td></tr></table></figure></p>\n<p>For a query like this, if we would’ve first received the users, then the posts for each user, then the comments for each post, then the author for each comments.\nWe would’ve blasted MongoDB with a lot of queries, and the number of queries increases exponentially. It can easily be around ~2000 for a simple query.</p>\n<p>However, using the <em>Hypernova</em> module, an innovative approach, the query above is executed with only 4 queries. \nBecause we have 4 collection nodes: “users”, “posts”, “comments” and “author”</p>\n<p>It does this by aggregating filters and reassembles data locally.</p>\n<p>From 2000 queries to 4 queries we experienced around 40x percent performance boost. </p>\n<h2 id=\"React-Integration\"><a href=\"#React-Integration\" class=\"headerlink\" title=\"React Integration\"></a>React Integration</h2><p>For integration with React try out <a href=\"https://github.com/cult-of-coders/grapher-react\">cultofcoders:grapher-react</a> package</p>\n"},{"title":"Grapher Boilerplate","description":"A meteor bootstrap project with Grapher and Grapher-Live and Demo Data","_content":"\n### Install\n\n```bash\ngit clone https://github.com/cult-of-coders/grapher-boilerplate\ncd grapher-boilerplate\nmeteor npm install\nmeteor\n```\n\nOr check it live:\nhttp://grapher-live.cultofcoders.com\n\n### Fixtures\n\nCurrently we have demo data and it is linked like this:\n\n- Users has many posts\n- Posts has many comments\n- Posts belong in a Group\n- Users belong in multiple Groups\n- Comment has one User\n\n### Sample Queries\n\nTo fetch all posts with their comments and their authors in Grapher Live:\n\n```js\n{\n posts: {\n title: 1,\n comments: {\n text: 1,\n user: {\n profile: 1\n }\n }\n }\n}\n```\n\n### Fetch only \"Good\" comments:\n\n```js\n{\n posts: {\n comments: {\n $filters: {text: \"Good\"}\n }\n }\n}\n```\n\n### Use sorting options\n\n```js\n{\n posts: {\n $options: {\n $sort: {title: -1}\n },\n title: 1,\n owner: {\n profile: 1\n }\n }\n}\n```","source":"packages/boilerplate.md","raw":"---\ntitle: Grapher Boilerplate\ndescription: A meteor bootstrap project with Grapher and Grapher-Live and Demo Data\n---\n\n### Install\n\n```bash\ngit clone https://github.com/cult-of-coders/grapher-boilerplate\ncd grapher-boilerplate\nmeteor npm install\nmeteor\n```\n\nOr check it live:\nhttp://grapher-live.cultofcoders.com\n\n### Fixtures\n\nCurrently we have demo data and it is linked like this:\n\n- Users has many posts\n- Posts has many comments\n- Posts belong in a Group\n- Users belong in multiple Groups\n- Comment has one User\n\n### Sample Queries\n\nTo fetch all posts with their comments and their authors in Grapher Live:\n\n```js\n{\n posts: {\n title: 1,\n comments: {\n text: 1,\n user: {\n profile: 1\n }\n }\n }\n}\n```\n\n### Fetch only \"Good\" comments:\n\n```js\n{\n posts: {\n comments: {\n $filters: {text: \"Good\"}\n }\n }\n}\n```\n\n### Use sorting options\n\n```js\n{\n posts: {\n $options: {\n $sort: {title: -1}\n },\n title: 1,\n owner: {\n profile: 1\n }\n }\n}\n```","date":"2016-11-21T12:20:53.648Z","updated":"2016-11-21T12:20:53.648Z","path":"packages/boilerplate.html","_id":"citl2ab5k0000ttjxl9jq5u7u","comments":1,"layout":"page","content":"<h3 id=\"Install\"><a href=\"#Install\" class=\"headerlink\" title=\"Install\"></a>Install</h3><figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div></pre></td><td class=\"code\"><pre><div class=\"line\">git <span class=\"built_in\">clone</span> https://github.com/cult-of-coders/grapher-boilerplate</div><div class=\"line\"><span class=\"built_in\">cd</span> grapher-boilerplate</div><div class=\"line\">meteor npm install</div><div class=\"line\">meteor</div></pre></td></tr></table></figure>\n<p>Or check it live:\n<a href=\"http://grapher-live.cultofcoders.com\" target=\"_blank\" rel=\"external\">http://grapher-live.cultofcoders.com</a></p>\n<h3 id=\"Fixtures\"><a href=\"#Fixtures\" class=\"headerlink\" title=\"Fixtures\"></a>Fixtures</h3><p>Currently we have demo data and it is linked like this:</p>\n<ul>\n<li>Users has many posts</li>\n<li>Posts has many comments</li>\n<li>Posts belong in a Group</li>\n<li>Users belong in multiple Groups</li>\n<li>Comment has one User</li>\n</ul>\n<h3 id=\"Sample-Queries\"><a href=\"#Sample-Queries\" class=\"headerlink\" title=\"Sample Queries\"></a>Sample Queries</h3><p>To fetch all posts with their comments and their authors in Grapher Live:</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div></pre></td><td class=\"code\"><pre><div class=\"line\">{</div><div class=\"line\"> <span class=\"attr\">posts</span>: {</div><div class=\"line\"> <span class=\"attr\">title</span>: <span class=\"number\">1</span>,</div><div class=\"line\"> <span class=\"attr\">comments</span>: {</div><div class=\"line\"> <span class=\"attr\">text</span>: <span class=\"number\">1</span>,</div><div class=\"line\"> <span class=\"attr\">user</span>: {</div><div class=\"line\"> <span class=\"attr\">profile</span>: <span class=\"number\">1</span></div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\">}</div></pre></td></tr></table></figure>\n<h3 id=\"Fetch-only-“Good”-comments\"><a href=\"#Fetch-only-“Good”-comments\" class=\"headerlink\" title=\"Fetch only “Good” comments:\"></a>Fetch only “Good” comments:</h3><figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div></pre></td><td class=\"code\"><pre><div class=\"line\">{</div><div class=\"line\"> <span class=\"attr\">posts</span>: {</div><div class=\"line\"> <span class=\"attr\">comments</span>: {</div><div class=\"line\"> <span class=\"attr\">$filters</span>: {<span class=\"attr\">text</span>: <span class=\"string\">\"Good\"</span>}</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\">}</div></pre></td></tr></table></figure>\n<h3 id=\"Use-sorting-options\"><a href=\"#Use-sorting-options\" class=\"headerlink\" title=\"Use sorting options\"></a>Use sorting options</h3><figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div></pre></td><td class=\"code\"><pre><div class=\"line\">{</div><div class=\"line\"> <span class=\"attr\">posts</span>: {</div><div class=\"line\"> <span class=\"attr\">$options</span>: {</div><div class=\"line\"> <span class=\"attr\">$sort</span>: {<span class=\"attr\">title</span>: <span class=\"number\">-1</span>}</div><div class=\"line\"> },</div><div class=\"line\"> <span class=\"attr\">title</span>: <span class=\"number\">1</span>,</div><div class=\"line\"> <span class=\"attr\">owner</span>: {</div><div class=\"line\"> <span class=\"attr\">profile</span>: <span class=\"number\">1</span></div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\">}</div></pre></td></tr></table></figure>","excerpt":"","more":"<h3 id=\"Install\"><a href=\"#Install\" class=\"headerlink\" title=\"Install\"></a>Install</h3><figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div></pre></td><td class=\"code\"><pre><div class=\"line\">git <span class=\"built_in\">clone</span> https://github.com/cult-of-coders/grapher-boilerplate</div><div class=\"line\"><span class=\"built_in\">cd</span> grapher-boilerplate</div><div class=\"line\">meteor npm install</div><div class=\"line\">meteor</div></pre></td></tr></table></figure>\n<p>Or check it live:\n<a href=\"http://grapher-live.cultofcoders.com\">http://grapher-live.cultofcoders.com</a></p>\n<h3 id=\"Fixtures\"><a href=\"#Fixtures\" class=\"headerlink\" title=\"Fixtures\"></a>Fixtures</h3><p>Currently we have demo data and it is linked like this:</p>\n<ul>\n<li>Users has many posts</li>\n<li>Posts has many comments</li>\n<li>Posts belong in a Group</li>\n<li>Users belong in multiple Groups</li>\n<li>Comment has one User</li>\n</ul>\n<h3 id=\"Sample-Queries\"><a href=\"#Sample-Queries\" class=\"headerlink\" title=\"Sample Queries\"></a>Sample Queries</h3><p>To fetch all posts with their comments and their authors in Grapher Live:</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div></pre></td><td class=\"code\"><pre><div class=\"line\">{</div><div class=\"line\"> <span class=\"attr\">posts</span>: {</div><div class=\"line\"> <span class=\"attr\">title</span>: <span class=\"number\">1</span>,</div><div class=\"line\"> <span class=\"attr\">comments</span>: {</div><div class=\"line\"> <span class=\"attr\">text</span>: <span class=\"number\">1</span>,</div><div class=\"line\"> <span class=\"attr\">user</span>: {</div><div class=\"line\"> <span class=\"attr\">profile</span>: <span class=\"number\">1</span></div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\">}</div></pre></td></tr></table></figure>\n<h3 id=\"Fetch-only-“Good”-comments\"><a href=\"#Fetch-only-“Good”-comments\" class=\"headerlink\" title=\"Fetch only “Good” comments:\"></a>Fetch only “Good” comments:</h3><figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div></pre></td><td class=\"code\"><pre><div class=\"line\">{</div><div class=\"line\"> <span class=\"attr\">posts</span>: {</div><div class=\"line\"> <span class=\"attr\">comments</span>: {</div><div class=\"line\"> <span class=\"attr\">$filters</span>: {<span class=\"attr\">text</span>: <span class=\"string\">\"Good\"</span>}</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\">}</div></pre></td></tr></table></figure>\n<h3 id=\"Use-sorting-options\"><a href=\"#Use-sorting-options\" class=\"headerlink\" title=\"Use sorting options\"></a>Use sorting options</h3><figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div></pre></td><td class=\"code\"><pre><div class=\"line\">{</div><div class=\"line\"> <span class=\"attr\">posts</span>: {</div><div class=\"line\"> <span class=\"attr\">$options</span>: {</div><div class=\"line\"> <span class=\"attr\">$sort</span>: {<span class=\"attr\">title</span>: <span class=\"number\">-1</span>}</div><div class=\"line\"> },</div><div class=\"line\"> <span class=\"attr\">title</span>: <span class=\"number\">1</span>,</div><div class=\"line\"> <span class=\"attr\">owner</span>: {</div><div class=\"line\"> <span class=\"attr\">profile</span>: <span class=\"number\">1</span></div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\">}</div></pre></td></tr></table></figure>"},{"title":"Grapher Live","description":"A meteor package that allows you to test your queries live.","_content":"\n### Install\n\n```bash\nmeteor add cultofcoders:grapher-live\nmeteor npm install --save-dev react react-ace\n```\n\n### Server Side Setup\n```js\n// in your /imports/startup/server\n// don't initialize it in your production environment, or it will lead to unwanted data exposure.\n\nimport { initialize } from 'meteor/cultofcoders:grapher-live';\n\ninitialize(); // exposes a method \"grapher_live\", used by the React Component\n```\n\n### Client Side Setup\n```js\n// client side expose a route using your router\n// example with FlowRouter\n// don't initialize this in production environment\n\nimport { render } from 'react-dom';\nimport { GrapherLive } from 'meteor/cultofcoders:grapher-live';\n\nFlowRouter.route('/grapher', () => {\n render(<GrapherLive />, document.getElementById('app')); \n // where app is your main id to render stuff (you can also use \"render-target\")\n})\n```\n\n### Usage\n\nGrapher Live uses *createQuery*:\n\n```js\n// query\n{\n tasks: {\n $filter({filters, params}) {\n filters.isChecked = params.isChecked;\n }\n }\n}\n\n// params example\n{\n isChecked: true\n}\n```","source":"packages/live.md","raw":"---\ntitle: Grapher Live\ndescription: A meteor package that allows you to test your queries live.\n---\n\n### Install\n\n```bash\nmeteor add cultofcoders:grapher-live\nmeteor npm install --save-dev react react-ace\n```\n\n### Server Side Setup\n```js\n// in your /imports/startup/server\n// don't initialize it in your production environment, or it will lead to unwanted data exposure.\n\nimport { initialize } from 'meteor/cultofcoders:grapher-live';\n\ninitialize(); // exposes a method \"grapher_live\", used by the React Component\n```\n\n### Client Side Setup\n```js\n// client side expose a route using your router\n// example with FlowRouter\n// don't initialize this in production environment\n\nimport { render } from 'react-dom';\nimport { GrapherLive } from 'meteor/cultofcoders:grapher-live';\n\nFlowRouter.route('/grapher', () => {\n render(<GrapherLive />, document.getElementById('app')); \n // where app is your main id to render stuff (you can also use \"render-target\")\n})\n```\n\n### Usage\n\nGrapher Live uses *createQuery*:\n\n```js\n// query\n{\n tasks: {\n $filter({filters, params}) {\n filters.isChecked = params.isChecked;\n }\n }\n}\n\n// params example\n{\n isChecked: true\n}\n```","date":"2016-11-21T12:20:53.652Z","updated":"2016-11-21T12:20:53.652Z","path":"packages/live.html","_id":"citl2aed00001ttjxkobyuinb","comments":1,"layout":"page","content":"<h3 id=\"Install\"><a href=\"#Install\" class=\"headerlink\" title=\"Install\"></a>Install</h3><figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div></pre></td><td class=\"code\"><pre><div class=\"line\">meteor add cultofcoders:grapher-live</div><div class=\"line\">meteor npm install --save-dev react react-ace</div></pre></td></tr></table></figure>\n<h3 id=\"Server-Side-Setup\"><a href=\"#Server-Side-Setup\" class=\"headerlink\" title=\"Server Side Setup\"></a>Server Side Setup</h3><figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">// in your /imports/startup/server</span></div><div class=\"line\"><span class=\"comment\">// don't initialize it in your production environment, or it will lead to unwanted data exposure.</span></div><div class=\"line\"></div><div class=\"line\"><span class=\"keyword\">import</span> { initialize } <span class=\"keyword\">from</span> <span class=\"string\">'meteor/cultofcoders:grapher-live'</span>;</div><div class=\"line\"></div><div class=\"line\">initialize(); <span class=\"comment\">// exposes a method \"grapher_live\", used by the React Component</span></div></pre></td></tr></table></figure>\n<h3 id=\"Client-Side-Setup\"><a href=\"#Client-Side-Setup\" class=\"headerlink\" title=\"Client Side Setup\"></a>Client Side Setup</h3><figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">// client side expose a route using your router</span></div><div class=\"line\"><span class=\"comment\">// example with FlowRouter</span></div><div class=\"line\"><span class=\"comment\">// don't initialize this in production environment</span></div><div class=\"line\"></div><div class=\"line\"><span class=\"keyword\">import</span> { render } <span class=\"keyword\">from</span> <span class=\"string\">'react-dom'</span>;</div><div class=\"line\"><span class=\"keyword\">import</span> { GrapherLive } <span class=\"keyword\">from</span> <span class=\"string\">'meteor/cultofcoders:grapher-live'</span>;</div><div class=\"line\"></div><div class=\"line\">FlowRouter.route(<span class=\"string\">'/grapher'</span>, () => {</div><div class=\"line\"> render(<GrapherLive />, document.getElementById('app')); </div><div class=\"line\"> // where app is your main id to render stuff (you can also use \"render-target\")</div><div class=\"line\">})</div></pre></td></tr></table></figure>\n<h3 id=\"Usage\"><a href=\"#Usage\" class=\"headerlink\" title=\"Usage\"></a>Usage</h3><p>Grapher Live uses <em>createQuery</em>:</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">// query</span></div><div class=\"line\">{</div><div class=\"line\"> <span class=\"attr\">tasks</span>: {</div><div class=\"line\"> $filter({filters, params}) {</div><div class=\"line\"> filters.isChecked = params.isChecked;</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\">}</div><div class=\"line\"></div><div class=\"line\"><span class=\"comment\">// params example</span></div><div class=\"line\">{</div><div class=\"line\"> <span class=\"attr\">isChecked</span>: <span class=\"literal\">true</span></div><div class=\"line\">}</div></pre></td></tr></table></figure>","excerpt":"","more":"<h3 id=\"Install\"><a href=\"#Install\" class=\"headerlink\" title=\"Install\"></a>Install</h3><figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div></pre></td><td class=\"code\"><pre><div class=\"line\">meteor add cultofcoders:grapher-live</div><div class=\"line\">meteor npm install --save-dev react react-ace</div></pre></td></tr></table></figure>\n<h3 id=\"Server-Side-Setup\"><a href=\"#Server-Side-Setup\" class=\"headerlink\" title=\"Server Side Setup\"></a>Server Side Setup</h3><figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">// in your /imports/startup/server</span></div><div class=\"line\"><span class=\"comment\">// don't initialize it in your production environment, or it will lead to unwanted data exposure.</span></div><div class=\"line\"></div><div class=\"line\"><span class=\"keyword\">import</span> { initialize } <span class=\"keyword\">from</span> <span class=\"string\">'meteor/cultofcoders:grapher-live'</span>;</div><div class=\"line\"></div><div class=\"line\">initialize(); <span class=\"comment\">// exposes a method \"grapher_live\", used by the React Component</span></div></pre></td></tr></table></figure>\n<h3 id=\"Client-Side-Setup\"><a href=\"#Client-Side-Setup\" class=\"headerlink\" title=\"Client Side Setup\"></a>Client Side Setup</h3><figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">// client side expose a route using your router</span></div><div class=\"line\"><span class=\"comment\">// example with FlowRouter</span></div><div class=\"line\"><span class=\"comment\">// don't initialize this in production environment</span></div><div class=\"line\"></div><div class=\"line\"><span class=\"keyword\">import</span> { render } <span class=\"keyword\">from</span> <span class=\"string\">'react-dom'</span>;</div><div class=\"line\"><span class=\"keyword\">import</span> { GrapherLive } <span class=\"keyword\">from</span> <span class=\"string\">'meteor/cultofcoders:grapher-live'</span>;</div><div class=\"line\"></div><div class=\"line\">FlowRouter.route(<span class=\"string\">'/grapher'</span>, () => {</div><div class=\"line\"> render(<GrapherLive />, document.getElementById('app')); </div><div class=\"line\"> // where app is your main id to render stuff (you can also use \"render-target\")</div><div class=\"line\">})</div></pre></td></tr></table></figure>\n<h3 id=\"Usage\"><a href=\"#Usage\" class=\"headerlink\" title=\"Usage\"></a>Usage</h3><p>Grapher Live uses <em>createQuery</em>:</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">// query</span></div><div class=\"line\">{</div><div class=\"line\"> <span class=\"attr\">tasks</span>: {</div><div class=\"line\"> $filter({filters, params}) {</div><div class=\"line\"> filters.isChecked = params.isChecked;</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\">}</div><div class=\"line\"></div><div class=\"line\"><span class=\"comment\">// params example</span></div><div class=\"line\">{</div><div class=\"line\"> <span class=\"attr\">isChecked</span>: <span class=\"literal\">true</span></div><div class=\"line\">}</div></pre></td></tr></table></figure>"},{"title":"Named Queries","description":"How to secure your queries via Named Queries","_content":"\n## Introduction\n\nNamed Queries are queries which have their form locked on the server. The reason for their existence\nis security. Imagine this scenario:\n- You have an Admin that can see all Users\n- You expose Users collection and check if he is Admin, you allow him\n- You have a collection Order which is linked to an EndUser and a TeamMember (both in Users collection)\n- As an EndUser when you see your order you want to see details about the assigned Team Member.\n- As an EndUser you cannot directly interogate \"users\" end-point, because you secured it for Admin Only\n- As an EndUser you cannot interogate \"orders\" and retrieve \"teamMember\" because exposures are linked\n\nWe have two options:\n- Bad Way: Manipulate exposure in such a manner to see if the user is EndUser and has an Order and the ids he wants to see\nare linked to an Order he has. But if you do that, then you may also need to restrict the fields he has access to and so on.\n- Good Way: Use named queries\n- Another good way: [Use exposure body](/guide/exposure.html#Exposure-Body)\n\n{% pullquote 'warning' %}\nNamedQuery is not affected by exposure at all. It has it's own firewall.\n{% endpullquote %}\n\n## Our First NamedQuery\n\n```js\n// /imports/api/queries/orderView.js\nimport { createNamedQuery } from 'meteor/cultofcoders:grapher';\n\nconst query = createdNamedQuery('ordersList', {\n orders: {\n $filter({ filters, params }) {\n filters.enduserId = params._id\n }\n details: 1,\n items: 1,\n teamMember: {\n profile: 1\n }\n }\n})\n\nexport default query;\n```\n\n## Fetching on Server\n\nWe have two ways of handling this on the server-side.\n\n### Importing the query\n\n```js\nimport query from '/imports/api/queries/ordersList';\n\nconst data = query.clone({_id: 'XXX'}).fetch();\n\n```\n{% pullquote 'warning' %}\nWe use .clone() method to avoid making changes on the actual query (like setParams). \nYou could do is export a factory that creates your query on the fly, however, for simplicity,\nwe created a .clone() method, that clones the query and it is completely isolated.\n{% endpullquote %}\n\n\n### Using: createQuery\n\nThis version has been designed to make it work with [Grapher-Live](https://github.com/cult-of-coders/grapher-live),\nso you can test your queries on the fly.\n\n```js\nimport query from '/imports/api/queries/ordersList';\n\nconst data = createQuery({\n ordersList: {\n _id: 'XXX' // Note these are the actual parameters.\n }\n}).fetch()\n```\n\n## Fetching on Client\n\nIn order to fetch it client-side, you need to expose this query server-side.\n\n```js\n// server-side code\nimport ordersListQuery from '/imports/api/queries/ordersList';\n\nordersListQuery.expose({\n firewall(userId, params) { // optional, but important!\n // throw exception or modify params to make it secure, in the example above we'll do\n params._id = userId\n }),\n method: true, // defaults to true, allows you to fetch it statically\n publication: true, // defaults to true, allows you to fetch it reactively,\n embody: { //optional\n // deep merges with the query body after the first node\n // this allows you to have full control over the query without exposing important business logic to the client\n teamMember: {\n $filters: {isActive: true}\n }\n }\n})\n\n// if you're just playing with it and want to see it works:\nordersListQuery.expose();\n```\n\n```js\n// client-side code\nimport ordersListQuery from '/imports/api/queries/ordersList';\n\nconst query = ordersListQuery.clone(params);\n\n// statically (Works exactly like a Normal Query)\nquery.fetch((err, data) => {}); // Works exactly like a Normal Query\n\n// reactively (Works exactly like a Normal Query)\nconst handle = query.subscribe(); \nquery.fetch();\n```\n\nIf you have imported the named query anywhere, then the name will be present in the store, meaning you can do:\n\n```js\n// client-side code\ncreateQuery({\n ordersListQuery: {params}\n}).fetch((err, data) => {\n // do something with the data\n});\n```\n\nIt removes the boilerplate of you having to clone it. the reason for this was to allow it to work with [Grapher-Live](https://github.com/cult-of-coders/grapher-live)\n\n## Why Collection Exposure ?\n\nYou might be asking at this stage, why do we still allow \"flexible\" queries via Collection Exposure. And it's a damn good question.\nIf your database is simple and can be easily secured then it is much simpler to avoid namedQueries and it's easier to expose an API,\nthrough which a client can request what he wants only, without having a lot of named queries.","source":"guide/namedQuery.md","raw":"---\ntitle: Named Queries\ndescription: How to secure your queries via Named Queries\n---\n\n## Introduction\n\nNamed Queries are queries which have their form locked on the server. The reason for their existence\nis security. Imagine this scenario:\n- You have an Admin that can see all Users\n- You expose Users collection and check if he is Admin, you allow him\n- You have a collection Order which is linked to an EndUser and a TeamMember (both in Users collection)\n- As an EndUser when you see your order you want to see details about the assigned Team Member.\n- As an EndUser you cannot directly interogate \"users\" end-point, because you secured it for Admin Only\n- As an EndUser you cannot interogate \"orders\" and retrieve \"teamMember\" because exposures are linked\n\nWe have two options:\n- Bad Way: Manipulate exposure in such a manner to see if the user is EndUser and has an Order and the ids he wants to see\nare linked to an Order he has. But if you do that, then you may also need to restrict the fields he has access to and so on.\n- Good Way: Use named queries\n- Another good way: [Use exposure body](/guide/exposure.html#Exposure-Body)\n\n{% pullquote 'warning' %}\nNamedQuery is not affected by exposure at all. It has it's own firewall.\n{% endpullquote %}\n\n## Our First NamedQuery\n\n```js\n// /imports/api/queries/orderView.js\nimport { createNamedQuery } from 'meteor/cultofcoders:grapher';\n\nconst query = createdNamedQuery('ordersList', {\n orders: {\n $filter({ filters, params }) {\n filters.enduserId = params._id\n }\n details: 1,\n items: 1,\n teamMember: {\n profile: 1\n }\n }\n})\n\nexport default query;\n```\n\n## Fetching on Server\n\nWe have two ways of handling this on the server-side.\n\n### Importing the query\n\n```js\nimport query from '/imports/api/queries/ordersList';\n\nconst data = query.clone({_id: 'XXX'}).fetch();\n\n```\n{% pullquote 'warning' %}\nWe use .clone() method to avoid making changes on the actual query (like setParams). \nYou could do is export a factory that creates your query on the fly, however, for simplicity,\nwe created a .clone() method, that clones the query and it is completely isolated.\n{% endpullquote %}\n\n\n### Using: createQuery\n\nThis version has been designed to make it work with [Grapher-Live](https://github.com/cult-of-coders/grapher-live),\nso you can test your queries on the fly.\n\n```js\nimport query from '/imports/api/queries/ordersList';\n\nconst data = createQuery({\n ordersList: {\n _id: 'XXX' // Note these are the actual parameters.\n }\n}).fetch()\n```\n\n## Fetching on Client\n\nIn order to fetch it client-side, you need to expose this query server-side.\n\n```js\n// server-side code\nimport ordersListQuery from '/imports/api/queries/ordersList';\n\nordersListQuery.expose({\n firewall(userId, params) { // optional, but important!\n // throw exception or modify params to make it secure, in the example above we'll do\n params._id = userId\n }),\n method: true, // defaults to true, allows you to fetch it statically\n publication: true, // defaults to true, allows you to fetch it reactively,\n embody: { //optional\n // deep merges with the query body after the first node\n // this allows you to have full control over the query without exposing important business logic to the client\n teamMember: {\n $filters: {isActive: true}\n }\n }\n})\n\n// if you're just playing with it and want to see it works:\nordersListQuery.expose();\n```\n\n```js\n// client-side code\nimport ordersListQuery from '/imports/api/queries/ordersList';\n\nconst query = ordersListQuery.clone(params);\n\n// statically (Works exactly like a Normal Query)\nquery.fetch((err, data) => {}); // Works exactly like a Normal Query\n\n// reactively (Works exactly like a Normal Query)\nconst handle = query.subscribe(); \nquery.fetch();\n```\n\nIf you have imported the named query anywhere, then the name will be present in the store, meaning you can do:\n\n```js\n// client-side code\ncreateQuery({\n ordersListQuery: {params}\n}).fetch((err, data) => {\n // do something with the data\n});\n```\n\nIt removes the boilerplate of you having to clone it. the reason for this was to allow it to work with [Grapher-Live](https://github.com/cult-of-coders/grapher-live)\n\n## Why Collection Exposure ?\n\nYou might be asking at this stage, why do we still allow \"flexible\" queries via Collection Exposure. And it's a damn good question.\nIf your database is simple and can be easily secured then it is much simpler to avoid namedQueries and it's easier to expose an API,\nthrough which a client can request what he wants only, without having a lot of named queries.","date":"2016-11-21T12:20:17.672Z","updated":"2016-11-21T12:20:17.672Z","path":"guide/namedQuery.html","_id":"citznejzq0001uejxw5fgu543","comments":1,"layout":"page","content":"<h2 id=\"Introduction\"><a href=\"#Introduction\" class=\"headerlink\" title=\"Introduction\"></a>Introduction</h2><p>Named Queries are queries which have their form locked on the server. The reason for their existence\nis security. Imagine this scenario:</p>\n<ul>\n<li>You have an Admin that can see all Users</li>\n<li>You expose Users collection and check if he is Admin, you allow him</li>\n<li>You have a collection Order which is linked to an EndUser and a TeamMember (both in Users collection)</li>\n<li>As an EndUser when you see your order you want to see details about the assigned Team Member.</li>\n<li>As an EndUser you cannot directly interogate “users” end-point, because you secured it for Admin Only</li>\n<li>As an EndUser you cannot interogate “orders” and retrieve “teamMember” because exposures are linked</li>\n</ul>\n<p>We have two options:</p>\n<ul>\n<li>Bad Way: Manipulate exposure in such a manner to see if the user is EndUser and has an Order and the ids he wants to see\nare linked to an Order he has. But if you do that, then you may also need to restrict the fields he has access to and so on.</li>\n<li>Good Way: Use named queries</li>\n<li>Another good way: <a href=\"/guide/exposure.html#Exposure-Body\">Use exposure body</a></li>\n</ul>\n<blockquote class=\"pullquote warning\"><p>NamedQuery is not affected by exposure at all. It has it’s own firewall.</p>\n</blockquote>\n<h2 id=\"Our-First-NamedQuery\"><a href=\"#Our-First-NamedQuery\" class=\"headerlink\" title=\"Our First NamedQuery\"></a>Our First NamedQuery</h2><figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">// /imports/api/queries/orderView.js</span></div><div class=\"line\"><span class=\"keyword\">import</span> { createNamedQuery } <span class=\"keyword\">from</span> <span class=\"string\">'meteor/cultofcoders:grapher'</span>;</div><div class=\"line\"></div><div class=\"line\"><span class=\"keyword\">const</span> query = createdNamedQuery(<span class=\"string\">'ordersList'</span>, {</div><div class=\"line\"> <span class=\"attr\">orders</span>: {</div><div class=\"line\"> $filter({ filters, params }) {</div><div class=\"line\"> filters.enduserId = params._id</div><div class=\"line\"> }</div><div class=\"line\"> details: <span class=\"number\">1</span>,</div><div class=\"line\"> <span class=\"attr\">items</span>: <span class=\"number\">1</span>,</div><div class=\"line\"> <span class=\"attr\">teamMember</span>: {</div><div class=\"line\"> <span class=\"attr\">profile</span>: <span class=\"number\">1</span></div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\">})</div><div class=\"line\"></div><div class=\"line\"><span class=\"keyword\">export</span> <span class=\"keyword\">default</span> query;</div></pre></td></tr></table></figure>\n<h2 id=\"Fetching-on-Server\"><a href=\"#Fetching-on-Server\" class=\"headerlink\" title=\"Fetching on Server\"></a>Fetching on Server</h2><p>We have two ways of handling this on the server-side.</p>\n<h3 id=\"Importing-the-query\"><a href=\"#Importing-the-query\" class=\"headerlink\" title=\"Importing the query\"></a>Importing the query</h3><figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">import</span> query <span class=\"keyword\">from</span> <span class=\"string\">'/imports/api/queries/ordersList'</span>;</div><div class=\"line\"></div><div class=\"line\"><span class=\"keyword\">const</span> data = query.clone({<span class=\"attr\">_id</span>: <span class=\"string\">'XXX'</span>}).fetch();</div></pre></td></tr></table></figure>\n<blockquote class=\"pullquote warning\"><p>We use .clone() method to avoid making changes on the actual query (like setParams). \nYou could do is export a factory that creates your query on the fly, however, for simplicity,\nwe created a .clone() method, that clones the query and it is completely isolated.</p>\n</blockquote>\n<h3 id=\"Using-createQuery\"><a href=\"#Using-createQuery\" class=\"headerlink\" title=\"Using: createQuery\"></a>Using: createQuery</h3><p>This version has been designed to make it work with <a href=\"https://github.com/cult-of-coders/grapher-live\" target=\"_blank\" rel=\"external\">Grapher-Live</a>,\nso you can test your queries on the fly.</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">import</span> query <span class=\"keyword\">from</span> <span class=\"string\">'/imports/api/queries/ordersList'</span>;</div><div class=\"line\"></div><div class=\"line\"><span class=\"keyword\">const</span> data = createQuery({</div><div class=\"line\"> <span class=\"attr\">ordersList</span>: {</div><div class=\"line\"> <span class=\"attr\">_id</span>: <span class=\"string\">'XXX'</span> <span class=\"comment\">// Note these are the actual parameters.</span></div><div class=\"line\"> }</div><div class=\"line\">}).fetch()</div></pre></td></tr></table></figure>\n<h2 id=\"Fetching-on-Client\"><a href=\"#Fetching-on-Client\" class=\"headerlink\" title=\"Fetching on Client\"></a>Fetching on Client</h2><p>In order to fetch it client-side, you need to expose this query server-side.</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div><div class=\"line\">20</div><div class=\"line\">21</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">// server-side code</span></div><div class=\"line\"><span class=\"keyword\">import</span> ordersListQuery <span class=\"keyword\">from</span> <span class=\"string\">'/imports/api/queries/ordersList'</span>;</div><div class=\"line\"></div><div class=\"line\">ordersListQuery.expose({</div><div class=\"line\"> firewall(userId, params) { <span class=\"comment\">// optional, but important!</span></div><div class=\"line\"> <span class=\"comment\">// throw exception or modify params to make it secure, in the example above we'll do</span></div><div class=\"line\"> params._id = userId</div><div class=\"line\"> }),</div><div class=\"line\"> <span class=\"attr\">method</span>: <span class=\"literal\">true</span>, <span class=\"comment\">// defaults to true, allows you to fetch it statically</span></div><div class=\"line\"> publication: <span class=\"literal\">true</span>, <span class=\"comment\">// defaults to true, allows you to fetch it reactively,</span></div><div class=\"line\"> embody: { <span class=\"comment\">//optional</span></div><div class=\"line\"> <span class=\"comment\">// deep merges with the query body after the first node</span></div><div class=\"line\"> <span class=\"comment\">// this allows you to have full control over the query without exposing important business logic to the client</span></div><div class=\"line\"> teamMember: {</div><div class=\"line\"> <span class=\"attr\">$filters</span>: {<span class=\"attr\">isActive</span>: <span class=\"literal\">true</span>}</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\">})</div><div class=\"line\"></div><div class=\"line\"><span class=\"comment\">// if you're just playing with it and want to see it works:</span></div><div class=\"line\">ordersListQuery.expose();</div></pre></td></tr></table></figure>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">// client-side code</span></div><div class=\"line\"><span class=\"keyword\">import</span> ordersListQuery <span class=\"keyword\">from</span> <span class=\"string\">'/imports/api/queries/ordersList'</span>;</div><div class=\"line\"></div><div class=\"line\"><span class=\"keyword\">const</span> query = ordersListQuery.clone(params);</div><div class=\"line\"></div><div class=\"line\"><span class=\"comment\">// statically (Works exactly like a Normal Query)</span></div><div class=\"line\">query.fetch(<span class=\"function\">(<span class=\"params\">err, data</span>) =></span> {}); <span class=\"comment\">// Works exactly like a Normal Query</span></div><div class=\"line\"></div><div class=\"line\"><span class=\"comment\">// reactively (Works exactly like a Normal Query)</span></div><div class=\"line\"><span class=\"keyword\">const</span> handle = query.subscribe(); </div><div class=\"line\">query.fetch();</div></pre></td></tr></table></figure>\n<p>If you have imported the named query anywhere, then the name will be present in the store, meaning you can do:</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">// client-side code</span></div><div class=\"line\">createQuery({</div><div class=\"line\"> <span class=\"attr\">ordersListQuery</span>: {params}</div><div class=\"line\">}).fetch(<span class=\"function\">(<span class=\"params\">err, data</span>) =></span> {</div><div class=\"line\"> <span class=\"comment\">// do something with the data</span></div><div class=\"line\">});</div></pre></td></tr></table></figure>\n<p>It removes the boilerplate of you having to clone it. the reason for this was to allow it to work with <a href=\"https://github.com/cult-of-coders/grapher-live\" target=\"_blank\" rel=\"external\">Grapher-Live</a></p>\n<h2 id=\"Why-Collection-Exposure\"><a href=\"#Why-Collection-Exposure\" class=\"headerlink\" title=\"Why Collection Exposure ?\"></a>Why Collection Exposure ?</h2><p>You might be asking at this stage, why do we still allow “flexible” queries via Collection Exposure. And it’s a damn good question.\nIf your database is simple and can be easily secured then it is much simpler to avoid namedQueries and it’s easier to expose an API,\nthrough which a client can request what he wants only, without having a lot of named queries.</p>\n","excerpt":"","more":"<h2 id=\"Introduction\"><a href=\"#Introduction\" class=\"headerlink\" title=\"Introduction\"></a>Introduction</h2><p>Named Queries are queries which have their form locked on the server. The reason for their existence\nis security. Imagine this scenario:</p>\n<ul>\n<li>You have an Admin that can see all Users</li>\n<li>You expose Users collection and check if he is Admin, you allow him</li>\n<li>You have a collection Order which is linked to an EndUser and a TeamMember (both in Users collection)</li>\n<li>As an EndUser when you see your order you want to see details about the assigned Team Member.</li>\n<li>As an EndUser you cannot directly interogate “users” end-point, because you secured it for Admin Only</li>\n<li>As an EndUser you cannot interogate “orders” and retrieve “teamMember” because exposures are linked</li>\n</ul>\n<p>We have two options:</p>\n<ul>\n<li>Bad Way: Manipulate exposure in such a manner to see if the user is EndUser and has an Order and the ids he wants to see\nare linked to an Order he has. But if you do that, then you may also need to restrict the fields he has access to and so on.</li>\n<li>Good Way: Use named queries</li>\n<li>Another good way: <a href=\"/guide/exposure.html#Exposure-Body\">Use exposure body</a></li>\n</ul>\n<blockquote class=\"pullquote warning\"><p>NamedQuery is not affected by exposure at all. It has it’s own firewall.</p>\n</blockquote>\n<h2 id=\"Our-First-NamedQuery\"><a href=\"#Our-First-NamedQuery\" class=\"headerlink\" title=\"Our First NamedQuery\"></a>Our First NamedQuery</h2><figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">// /imports/api/queries/orderView.js</span></div><div class=\"line\"><span class=\"keyword\">import</span> { createNamedQuery } <span class=\"keyword\">from</span> <span class=\"string\">'meteor/cultofcoders:grapher'</span>;</div><div class=\"line\"></div><div class=\"line\"><span class=\"keyword\">const</span> query = createdNamedQuery(<span class=\"string\">'ordersList'</span>, {</div><div class=\"line\"> <span class=\"attr\">orders</span>: {</div><div class=\"line\"> $filter({ filters, params }) {</div><div class=\"line\"> filters.enduserId = params._id</div><div class=\"line\"> }</div><div class=\"line\"> details: <span class=\"number\">1</span>,</div><div class=\"line\"> <span class=\"attr\">items</span>: <span class=\"number\">1</span>,</div><div class=\"line\"> <span class=\"attr\">teamMember</span>: {</div><div class=\"line\"> <span class=\"attr\">profile</span>: <span class=\"number\">1</span></div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\">})</div><div class=\"line\"></div><div class=\"line\"><span class=\"keyword\">export</span> <span class=\"keyword\">default</span> query;</div></pre></td></tr></table></figure>\n<h2 id=\"Fetching-on-Server\"><a href=\"#Fetching-on-Server\" class=\"headerlink\" title=\"Fetching on Server\"></a>Fetching on Server</h2><p>We have two ways of handling this on the server-side.</p>\n<h3 id=\"Importing-the-query\"><a href=\"#Importing-the-query\" class=\"headerlink\" title=\"Importing the query\"></a>Importing the query</h3><figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">import</span> query <span class=\"keyword\">from</span> <span class=\"string\">'/imports/api/queries/ordersList'</span>;</div><div class=\"line\"></div><div class=\"line\"><span class=\"keyword\">const</span> data = query.clone({<span class=\"attr\">_id</span>: <span class=\"string\">'XXX'</span>}).fetch();</div></pre></td></tr></table></figure>\n<blockquote class=\"pullquote warning\"><p>We use .clone() method to avoid making changes on the actual query (like setParams). \nYou could do is export a factory that creates your query on the fly, however, for simplicity,\nwe created a .clone() method, that clones the query and it is completely isolated.</p>\n</blockquote>\n<h3 id=\"Using-createQuery\"><a href=\"#Using-createQuery\" class=\"headerlink\" title=\"Using: createQuery\"></a>Using: createQuery</h3><p>This version has been designed to make it work with <a href=\"https://github.com/cult-of-coders/grapher-live\">Grapher-Live</a>,\nso you can test your queries on the fly.</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">import</span> query <span class=\"keyword\">from</span> <span class=\"string\">'/imports/api/queries/ordersList'</span>;</div><div class=\"line\"></div><div class=\"line\"><span class=\"keyword\">const</span> data = createQuery({</div><div class=\"line\"> <span class=\"attr\">ordersList</span>: {</div><div class=\"line\"> <span class=\"attr\">_id</span>: <span class=\"string\">'XXX'</span> <span class=\"comment\">// Note these are the actual parameters.</span></div><div class=\"line\"> }</div><div class=\"line\">}).fetch()</div></pre></td></tr></table></figure>\n<h2 id=\"Fetching-on-Client\"><a href=\"#Fetching-on-Client\" class=\"headerlink\" title=\"Fetching on Client\"></a>Fetching on Client</h2><p>In order to fetch it client-side, you need to expose this query server-side.</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div><div class=\"line\">20</div><div class=\"line\">21</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">// server-side code</span></div><div class=\"line\"><span class=\"keyword\">import</span> ordersListQuery <span class=\"keyword\">from</span> <span class=\"string\">'/imports/api/queries/ordersList'</span>;</div><div class=\"line\"></div><div class=\"line\">ordersListQuery.expose({</div><div class=\"line\"> firewall(userId, params) { <span class=\"comment\">// optional, but important!</span></div><div class=\"line\"> <span class=\"comment\">// throw exception or modify params to make it secure, in the example above we'll do</span></div><div class=\"line\"> params._id = userId</div><div class=\"line\"> }),</div><div class=\"line\"> <span class=\"attr\">method</span>: <span class=\"literal\">true</span>, <span class=\"comment\">// defaults to true, allows you to fetch it statically</span></div><div class=\"line\"> publication: <span class=\"literal\">true</span>, <span class=\"comment\">// defaults to true, allows you to fetch it reactively,</span></div><div class=\"line\"> embody: { <span class=\"comment\">//optional</span></div><div class=\"line\"> <span class=\"comment\">// deep merges with the query body after the first node</span></div><div class=\"line\"> <span class=\"comment\">// this allows you to have full control over the query without exposing important business logic to the client</span></div><div class=\"line\"> teamMember: {</div><div class=\"line\"> <span class=\"attr\">$filters</span>: {<span class=\"attr\">isActive</span>: <span class=\"literal\">true</span>}</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\">})</div><div class=\"line\"></div><div class=\"line\"><span class=\"comment\">// if you're just playing with it and want to see it works:</span></div><div class=\"line\">ordersListQuery.expose();</div></pre></td></tr></table></figure>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">// client-side code</span></div><div class=\"line\"><span class=\"keyword\">import</span> ordersListQuery <span class=\"keyword\">from</span> <span class=\"string\">'/imports/api/queries/ordersList'</span>;</div><div class=\"line\"></div><div class=\"line\"><span class=\"keyword\">const</span> query = ordersListQuery.clone(params);</div><div class=\"line\"></div><div class=\"line\"><span class=\"comment\">// statically (Works exactly like a Normal Query)</span></div><div class=\"line\">query.fetch(<span class=\"function\">(<span class=\"params\">err, data</span>) =></span> {}); <span class=\"comment\">// Works exactly like a Normal Query</span></div><div class=\"line\"></div><div class=\"line\"><span class=\"comment\">// reactively (Works exactly like a Normal Query)</span></div><div class=\"line\"><span class=\"keyword\">const</span> handle = query.subscribe(); </div><div class=\"line\">query.fetch();</div></pre></td></tr></table></figure>\n<p>If you have imported the named query anywhere, then the name will be present in the store, meaning you can do:</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">// client-side code</span></div><div class=\"line\">createQuery({</div><div class=\"line\"> <span class=\"attr\">ordersListQuery</span>: {params}</div><div class=\"line\">}).fetch(<span class=\"function\">(<span class=\"params\">err, data</span>) =></span> {</div><div class=\"line\"> <span class=\"comment\">// do something with the data</span></div><div class=\"line\">});</div></pre></td></tr></table></figure>\n<p>It removes the boilerplate of you having to clone it. the reason for this was to allow it to work with <a href=\"https://github.com/cult-of-coders/grapher-live\">Grapher-Live</a></p>\n<h2 id=\"Why-Collection-Exposure\"><a href=\"#Why-Collection-Exposure\" class=\"headerlink\" title=\"Why Collection Exposure ?\"></a>Why Collection Exposure ?</h2><p>You might be asking at this stage, why do we still allow “flexible” queries via Collection Exposure. And it’s a damn good question.\nIf your database is simple and can be easily secured then it is much simpler to avoid namedQueries and it’s easier to expose an API,\nthrough which a client can request what he wants only, without having a lot of named queries.</p>\n"},{"title":"Exposing Collections","description":"Learn how to securely expose your queries for client fetching","_content":"\nCollection Exposure\n===================\n\nIn order to query for a collection from the client-side and fetch it or subscribe to it. You must expose it.\n\n\nExposing a collection does the following things:\n\n- Creates a method called: exposure_{collectionName} which accepts a query\n- Creates a publication called: exposure_{collectionName} which accepts a query and uses [reywood:publish-composite](https://atmospherejs.com/reywood/publish-composite) to achieve reactive relationships.\n- If firewall is specified, it extends *find* method of your collection, allowing an extra parameter:\n```\nCollection.find(filters, options, userId);\n```\n\n\n{% pullquote 'warning' %}\nIf *userId* is undefined, the firewall and constraints will not be applied. If the *userId* is *null*, the firewall will be applied. This is to allow server-side fetching without any restrictions.\n{% endpullquote %}\n\nExposing a collection to everyone\n---------------------------------\n\n```\nCollection.expose()\n```\n\nExposing a collection to logged in users\n----------------------------------------\n\n```\nCollection.expose({\n firewall(filters, options, userId) {\n if (!userId) {\n throw new Meteor.Error('...');\n }\n }\n});\n```\n\nEnforcing limits\n----------------\n\n```\nCollection.expose({\n firewall(filters, options, userId) {\n filters.userId = userId;\n }\n maxLimit: 100, // The publication/method will not allow data fetching for more than 100 items. (Performance related)\n maxDepth: 3 // The publication/method will not allow a query with more than 3 levels deep. (Performance related)\n restrictedFields: ['services', 'secretField'] // this will clean up filters, options.sort and options.fields and remove those fields from there.\n});\n```\n\n\nExposure firewalls are linked.\n------------------------------\n\nWhen querying for a data-graph like:\n```\n{\n users: {\n comments: {}\n }\n}\n```\n\nIt is not necessary to have an exposure for *comments*, however if you do have it, and it has a firewall. The firewall will be called.\nThe reason for this is security.\n\n{% pullquote 'warning' %}\nDon't worry about performance. We went great lengths to retrieve data in as few MongoDB requests as possible, in the scenario above,\nif you do have a firewall for users and comments, both will be called only once, because we only make 2 MongoDB requests.\n{% endpullquote %}\n\nGlobal Exposure Configuration\n-----------------------------\n```\nimport { Exposure } from 'meteor/cultofcoders:grapher';\n\n// Make sure you do this before exposing any collections.\nExposure.setConfig({\n firewall,\n maxLimit,\n maxDepth,\n restrictFields\n});\n```\n\n\nWhen you expose a collection, it will extend the global exposure methods.\nThe reason for this is you may want a global limit of 100, or you may want a maximum graph depth of 5 for all your exposed collections,\nwithout having to specify this for each.\n\nImportant: if global exposure has a firewall and the collection exposure has a firewall defined as welll, the collection exposure firewall will be applied. \n\n## Taming The Firewall\n\n```js\n// control what to show\n\nCollection.expose({\n firewall(filters, options, userId) => {\n if (!isAdmin(userId)) {\n filters.isVisible = true;\n }\n }\n});\n```\n\n```js\n// make certain fields invisible for certain users\nimport { Exposure } from 'meteor/cultofcoders:grapher'\nCollection.expose({\n firewall(filters, options, userId) => {\n if (!isAdmin(userId)) {\n Exposure.restrictFields(filters, options, ['privateData'])\n // it will remove all specified fields from filters, options.sort, options.fields\n // this way you will not expose unwanted data.\n }\n }\n});\n```\n\n## Restricting Links\n\nRestrict using a simple array:\n```js\nCollection.expose({\n restrictLinks: ['privateLink', 'anotherPrivateLink']\n});\n```\n\nCompute restricted links when fetching the query:\n```js\nCollection.expose({\n restrictLinks(userId) {\n return ['privateLink', 'anotherPrivateLink']\n }\n});\n```\n\n## Exposure Body \n\nCreating an exposure body basically states that:\n\"I allow the client to request anything he wants from what I allow him to.\"\n\nIf *body* is specified, it is first applied on the request and then the subsequent rules such as *restrictedFields*, *restrictLinks*, *firewall*\n\nThis is for advanced usage and it completes the security of exposure. \nThis may be a bit tricky to understand at first because there are many rules, but don't give up hope, it's quite easy.\n\n{% pullquote 'warning' %}\nBy using body, Grapher automatically assumes you have control over what you give, meaning all firewalls from other exposures for linked elements (if they exist) will be bypassed. But not the firewall of the current exposure.\n{% endpullquote %}\n\n### Basic Usage\n\n```js\nCollection.expose({\n body: {\n firstName: 1,\n link: {\n someField: 1\n }\n }\n})\n```\n\nIf you query from the *client-side* something like:\n```js\ncreateQuery({\n collection: {\n firstName: 1,\n lastName: 1,\n link: {\n someOtherField: 1\n }\n }\n})\n```\n\nThe intersected body will look like:\n```js\n{\n firstName: 1,\n link: {}\n}\n```\n\nOk, but what if I want to have a different body based on the userId ? Body can also be a function that takes in an userId, and returns an object.\n\n```js\nCollection.expose({\n body(userId) {\n let body = { firstName: 1 };\n \n if (isAdmin(userId)) {\n _.extend(body, { lastName: 1 })\n }\n \n return body;\n }\n})\n```\n\n{% pullquote 'warning' %}\nDeep nesting with other links not be allowed unless your *body* specifies it.\n{% endpullquote %}\n\nThe special fields \"$filters\" and \"$options\" are allowed at any link level (including root). However, they will go through a phase of cleaning,\nmeaning it will only allow to filter and sort for fields that exist in the body.\n\n\n{% pullquote 'warning' %}\nWe got your back covered!\n\nThis check goes deeply to verify \"$and\", \"$or\", \"$nin\" and \"$not\" special MongoDB selectors. This way you are sure you do not expose data you don't want to.\nBecause, given enough requests, a hacker playing with $filters and $sort options can figure out a field that you may not want to give him access to.\n{% endpullquote %}\n\nIf the *body* contains functions they will be computed before intersection. Each function will receive userId.\n```js\n{\n linkName(userId) { return {test: 1} }\n}\n\n// transforms into\n{\n linkName: {\n test: 1\n }\n}\n```\n\nYou can return *undefined* or *false* in your function if you want to disable the field/link for intersection.\n\n```js\n{\n linkName(userId) {\n if (isAdmin(userId)) {\n return object;\n }\n }\n}\n```\n\n### Linking Grapher Exposure Bodies\n\nYou can link bodies in your own way and also reference other bodies'links.\nFunctions are computed on-demand, meaning you can have self-referencing body functions:\n\n```js\n// Comments ONE link to Users as 'user' \n// Users INVERSED 'user' from Comments AS 'comments'\n\nconst commentBody = (userId) => {\n return {\n user: userBody\n text: 1\n }\n}\n\nconst userBody = (userId) => {\n if (isAdmin(userId)) {\n return {\n comments: commentBody\n }; \n }\n \n return somethingElse;\n}\n\nUsers.expose({\n body: userBody\n})\n\nComments.expose({\n body: commentBody\n})\n```\n\nThis will allow requests like:\n```js\n{\n users: {\n comments: {\n user: {\n // It doesn't make much sense for this case\n // but you can have \n }\n }\n }\n}\n```","source":"guide/exposure.md","raw":"---\ntitle: Exposing Collections\ndescription: Learn how to securely expose your queries for client fetching\n---\n\nCollection Exposure\n===================\n\nIn order to query for a collection from the client-side and fetch it or subscribe to it. You must expose it.\n\n\nExposing a collection does the following things:\n\n- Creates a method called: exposure_{collectionName} which accepts a query\n- Creates a publication called: exposure_{collectionName} which accepts a query and uses [reywood:publish-composite](https://atmospherejs.com/reywood/publish-composite) to achieve reactive relationships.\n- If firewall is specified, it extends *find* method of your collection, allowing an extra parameter:\n```\nCollection.find(filters, options, userId);\n```\n\n\n{% pullquote 'warning' %}\nIf *userId* is undefined, the firewall and constraints will not be applied. If the *userId* is *null*, the firewall will be applied. This is to allow server-side fetching without any restrictions.\n{% endpullquote %}\n\nExposing a collection to everyone\n---------------------------------\n\n```\nCollection.expose()\n```\n\nExposing a collection to logged in users\n----------------------------------------\n\n```\nCollection.expose({\n firewall(filters, options, userId) {\n if (!userId) {\n throw new Meteor.Error('...');\n }\n }\n});\n```\n\nEnforcing limits\n----------------\n\n```\nCollection.expose({\n firewall(filters, options, userId) {\n filters.userId = userId;\n }\n maxLimit: 100, // The publication/method will not allow data fetching for more than 100 items. (Performance related)\n maxDepth: 3 // The publication/method will not allow a query with more than 3 levels deep. (Performance related)\n restrictedFields: ['services', 'secretField'] // this will clean up filters, options.sort and options.fields and remove those fields from there.\n});\n```\n\n\nExposure firewalls are linked.\n------------------------------\n\nWhen querying for a data-graph like:\n```\n{\n users: {\n comments: {}\n }\n}\n```\n\nIt is not necessary to have an exposure for *comments*, however if you do have it, and it has a firewall. The firewall will be called.\nThe reason for this is security.\n\n{% pullquote 'warning' %}\nDon't worry about performance. We went great lengths to retrieve data in as few MongoDB requests as possible, in the scenario above,\nif you do have a firewall for users and comments, both will be called only once, because we only make 2 MongoDB requests.\n{% endpullquote %}\n\nGlobal Exposure Configuration\n-----------------------------\n```\nimport { Exposure } from 'meteor/cultofcoders:grapher';\n\n// Make sure you do this before exposing any collections.\nExposure.setConfig({\n firewall,\n maxLimit,\n maxDepth,\n restrictFields\n});\n```\n\n\nWhen you expose a collection, it will extend the global exposure methods.\nThe reason for this is you may want a global limit of 100, or you may want a maximum graph depth of 5 for all your exposed collections,\nwithout having to specify this for each.\n\nImportant: if global exposure has a firewall and the collection exposure has a firewall defined as welll, the collection exposure firewall will be applied. \n\n## Taming The Firewall\n\n```js\n// control what to show\n\nCollection.expose({\n firewall(filters, options, userId) => {\n if (!isAdmin(userId)) {\n filters.isVisible = true;\n }\n }\n});\n```\n\n```js\n// make certain fields invisible for certain users\nimport { Exposure } from 'meteor/cultofcoders:grapher'\nCollection.expose({\n firewall(filters, options, userId) => {\n if (!isAdmin(userId)) {\n Exposure.restrictFields(filters, options, ['privateData'])\n // it will remove all specified fields from filters, options.sort, options.fields\n // this way you will not expose unwanted data.\n }\n }\n});\n```\n\n## Restricting Links\n\nRestrict using a simple array:\n```js\nCollection.expose({\n restrictLinks: ['privateLink', 'anotherPrivateLink']\n});\n```\n\nCompute restricted links when fetching the query:\n```js\nCollection.expose({\n restrictLinks(userId) {\n return ['privateLink', 'anotherPrivateLink']\n }\n});\n```\n\n## Exposure Body \n\nCreating an exposure body basically states that:\n\"I allow the client to request anything he wants from what I allow him to.\"\n\nIf *body* is specified, it is first applied on the request and then the subsequent rules such as *restrictedFields*, *restrictLinks*, *firewall*\n\nThis is for advanced usage and it completes the security of exposure. \nThis may be a bit tricky to understand at first because there are many rules, but don't give up hope, it's quite easy.\n\n{% pullquote 'warning' %}\nBy using body, Grapher automatically assumes you have control over what you give, meaning all firewalls from other exposures for linked elements (if they exist) will be bypassed. But not the firewall of the current exposure.\n{% endpullquote %}\n\n### Basic Usage\n\n```js\nCollection.expose({\n body: {\n firstName: 1,\n link: {\n someField: 1\n }\n }\n})\n```\n\nIf you query from the *client-side* something like:\n```js\ncreateQuery({\n collection: {\n firstName: 1,\n lastName: 1,\n link: {\n someOtherField: 1\n }\n }\n})\n```\n\nThe intersected body will look like:\n```js\n{\n firstName: 1,\n link: {}\n}\n```\n\nOk, but what if I want to have a different body based on the userId ? Body can also be a function that takes in an userId, and returns an object.\n\n```js\nCollection.expose({\n body(userId) {\n let body = { firstName: 1 };\n \n if (isAdmin(userId)) {\n _.extend(body, { lastName: 1 })\n }\n \n return body;\n }\n})\n```\n\n{% pullquote 'warning' %}\nDeep nesting with other links not be allowed unless your *body* specifies it.\n{% endpullquote %}\n\nThe special fields \"$filters\" and \"$options\" are allowed at any link level (including root). However, they will go through a phase of cleaning,\nmeaning it will only allow to filter and sort for fields that exist in the body.\n\n\n{% pullquote 'warning' %}\nWe got your back covered!\n\nThis check goes deeply to verify \"$and\", \"$or\", \"$nin\" and \"$not\" special MongoDB selectors. This way you are sure you do not expose data you don't want to.\nBecause, given enough requests, a hacker playing with $filters and $sort options can figure out a field that you may not want to give him access to.\n{% endpullquote %}\n\nIf the *body* contains functions they will be computed before intersection. Each function will receive userId.\n```js\n{\n linkName(userId) { return {test: 1} }\n}\n\n// transforms into\n{\n linkName: {\n test: 1\n }\n}\n```\n\nYou can return *undefined* or *false* in your function if you want to disable the field/link for intersection.\n\n```js\n{\n linkName(userId) {\n if (isAdmin(userId)) {\n return object;\n }\n }\n}\n```\n\n### Linking Grapher Exposure Bodies\n\nYou can link bodies in your own way and also reference other bodies'links.\nFunctions are computed on-demand, meaning you can have self-referencing body functions:\n\n```js\n// Comments ONE link to Users as 'user' \n// Users INVERSED 'user' from Comments AS 'comments'\n\nconst commentBody = (userId) => {\n return {\n user: userBody\n text: 1\n }\n}\n\nconst userBody = (userId) => {\n if (isAdmin(userId)) {\n return {\n comments: commentBody\n }; \n }\n \n return somethingElse;\n}\n\nUsers.expose({\n body: userBody\n})\n\nComments.expose({\n body: commentBody\n})\n```\n\nThis will allow requests like:\n```js\n{\n users: {\n comments: {\n user: {\n // It doesn't make much sense for this case\n // but you can have \n }\n }\n }\n}\n```","date":"2016-11-21T12:20:17.672Z","updated":"2016-11-21T12:20:17.668Z","path":"guide/exposure.html","_id":"citzpa2ot0000dijxiy42su25","comments":1,"layout":"page","content":"<h1 id=\"Collection-Exposure\"><a href=\"#Collection-Exposure\" class=\"headerlink\" title=\"Collection Exposure\"></a>Collection Exposure</h1><p>In order to query for a collection from the client-side and fetch it or subscribe to it. You must expose it.</p>\n<p>Exposing a collection does the following things:</p>\n<ul>\n<li>Creates a method called: exposure_{collectionName} which accepts a query</li>\n<li>Creates a publication called: exposure_{collectionName} which accepts a query and uses <a href=\"https://atmospherejs.com/reywood/publish-composite\" target=\"_blank\" rel=\"external\">reywood:publish-composite</a> to achieve reactive relationships.</li>\n<li>If firewall is specified, it extends <em>find</em> method of your collection, allowing an extra parameter:<figure class=\"highlight gradle\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\">Collection.<span class=\"keyword\">find</span>(filters, <span class=\"keyword\">options</span>, userId);</div></pre></td></tr></table></figure>\n</li>\n</ul>\n<blockquote class=\"pullquote warning\"><p>If <em>userId</em> is undefined, the firewall and constraints will not be applied. If the <em>userId</em> is <em>null</em>, the firewall will be applied. This is to allow server-side fetching without any restrictions.</p>\n</blockquote>\n<h2 id=\"Exposing-a-collection-to-everyone\"><a href=\"#Exposing-a-collection-to-everyone\" class=\"headerlink\" title=\"Exposing a collection to everyone\"></a>Exposing a collection to everyone</h2><figure class=\"highlight coq\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">Collection</span>.expose()</div></pre></td></tr></table></figure>\n<h2 id=\"Exposing-a-collection-to-logged-in-users\"><a href=\"#Exposing-a-collection-to-logged-in-users\" class=\"headerlink\" title=\"Exposing a collection to logged in users\"></a>Exposing a collection to logged in users</h2><figure class=\"highlight gradle\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div></pre></td><td class=\"code\"><pre><div class=\"line\">Collection.expose({</div><div class=\"line\"> firewall(filters, <span class=\"keyword\">options</span>, userId) {</div><div class=\"line\"> <span class=\"keyword\">if</span> (!userId) {</div><div class=\"line\"> <span class=\"keyword\">throw</span> <span class=\"keyword\">new</span> Meteor.Error(<span class=\"string\">'...'</span>);</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\">});</div></pre></td></tr></table></figure>\n<h2 id=\"Enforcing-limits\"><a href=\"#Enforcing-limits\" class=\"headerlink\" title=\"Enforcing limits\"></a>Enforcing limits</h2><figure class=\"highlight gams\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div></pre></td><td class=\"code\"><pre><div class=\"line\">Collection.expose({</div><div class=\"line\"> firewall(filters, <span class=\"keyword\">options</span>, userId) {</div><div class=\"line\"> filters.userId = userId;</div><div class=\"line\"> }</div><div class=\"line\"> maxLimit: <span class=\"number\">100</span>, <span class=\"comment\">// The publication/method will not allow data fetching for more than 100 items. (Performance related)</span></div><div class=\"line\"> maxDepth: <span class=\"number\">3</span> <span class=\"comment\">// The publication/method will not allow a query with more than 3 levels deep. (Performance related)</span></div><div class=\"line\"> restrictedFields: [<span class=\"string\">'services'</span>, <span class=\"string\">'secretField'</span>] <span class=\"comment\">// this will clean up filters, options.sort and options.fields and remove those fields from there.</span></div><div class=\"line\">});</div></pre></td></tr></table></figure>\n<h2 id=\"Exposure-firewalls-are-linked\"><a href=\"#Exposure-firewalls-are-linked\" class=\"headerlink\" title=\"Exposure firewalls are linked.\"></a>Exposure firewalls are linked.</h2><p>When querying for a data-graph like:\n<figure class=\"highlight css\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div></pre></td><td class=\"code\"><pre><div class=\"line\">{</div><div class=\"line\"> <span class=\"attribute\">users</span>: {</div><div class=\"line\"> comments: {}</div><div class=\"line\"> }</div><div class=\"line\">}</div></pre></td></tr></table></figure></p>\n<p>It is not necessary to have an exposure for <em>comments</em>, however if you do have it, and it has a firewall. The firewall will be called.\nThe reason for this is security.</p>\n<blockquote class=\"pullquote warning\"><p>Don’t worry about performance. We went great lengths to retrieve data in as few MongoDB requests as possible, in the scenario above,\nif you do have a firewall for users and comments, both will be called only once, because we only make 2 MongoDB requests.</p>\n</blockquote>\n<h2 id=\"Global-Exposure-Configuration\"><a href=\"#Global-Exposure-Configuration\" class=\"headerlink\" title=\"Global Exposure Configuration\"></a>Global Exposure Configuration</h2><figure class=\"highlight javascript\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">import</span> { Exposure } <span class=\"keyword\">from</span> <span class=\"string\">'meteor/cultofcoders:grapher'</span>;</div><div class=\"line\"></div><div class=\"line\"><span class=\"comment\">// Make sure you do this before exposing any collections.</span></div><div class=\"line\">Exposure.setConfig({</div><div class=\"line\"> firewall,</div><div class=\"line\"> maxLimit,</div><div class=\"line\"> maxDepth,</div><div class=\"line\"> restrictFields</div><div class=\"line\">});</div></pre></td></tr></table></figure>\n<p>When you expose a collection, it will extend the global exposure methods.\nThe reason for this is you may want a global limit of 100, or you may want a maximum graph depth of 5 for all your exposed collections,\nwithout having to specify this for each.</p>\n<p>Important: if global exposure has a firewall and the collection exposure has a firewall defined as welll, the collection exposure firewall will be applied. </p>\n<h2 id=\"Taming-The-Firewall\"><a href=\"#Taming-The-Firewall\" class=\"headerlink\" title=\"Taming The Firewall\"></a>Taming The Firewall</h2><figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">// control what to show</span></div><div class=\"line\"></div><div class=\"line\">Collection.expose({</div><div class=\"line\"> firewall(filters, options, userId) => {</div><div class=\"line\"> <span class=\"keyword\">if</span> (!isAdmin(userId)) {</div><div class=\"line\"> filters.isVisible = <span class=\"literal\">true</span>;</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\">});</div></pre></td></tr></table></figure>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">// make certain fields invisible for certain users</span></div><div class=\"line\"><span class=\"keyword\">import</span> { Exposure } <span class=\"keyword\">from</span> <span class=\"string\">'meteor/cultofcoders:grapher'</span></div><div class=\"line\">Collection.expose({</div><div class=\"line\"> firewall(filters, options, userId) => {</div><div class=\"line\"> <span class=\"keyword\">if</span> (!isAdmin(userId)) {</div><div class=\"line\"> Exposure.restrictFields(filters, options, [<span class=\"string\">'privateData'</span>])</div><div class=\"line\"> <span class=\"comment\">// it will remove all specified fields from filters, options.sort, options.fields</span></div><div class=\"line\"> <span class=\"comment\">// this way you will not expose unwanted data.</span></div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\">});</div></pre></td></tr></table></figure>\n<h2 id=\"Restricting-Links\"><a href=\"#Restricting-Links\" class=\"headerlink\" title=\"Restricting Links\"></a>Restricting Links</h2><p>Restrict using a simple array:\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div></pre></td><td class=\"code\"><pre><div class=\"line\">Collection.expose({</div><div class=\"line\"> <span class=\"attr\">restrictLinks</span>: [<span class=\"string\">'privateLink'</span>, <span class=\"string\">'anotherPrivateLink'</span>]</div><div class=\"line\">});</div></pre></td></tr></table></figure></p>\n<p>Compute restricted links when fetching the query:\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div></pre></td><td class=\"code\"><pre><div class=\"line\">Collection.expose({</div><div class=\"line\"> restrictLinks(userId) {</div><div class=\"line\"> <span class=\"keyword\">return</span> [<span class=\"string\">'privateLink'</span>, <span class=\"string\">'anotherPrivateLink'</span>]</div><div class=\"line\"> }</div><div class=\"line\">});</div></pre></td></tr></table></figure></p>\n<h2 id=\"Exposure-Body\"><a href=\"#Exposure-Body\" class=\"headerlink\" title=\"Exposure Body\"></a>Exposure Body</h2><p>Creating an exposure body basically states that:\n“I allow the client to request anything he wants from what I allow him to.”</p>\n<p>If <em>body</em> is specified, it is first applied on the request and then the subsequent rules such as <em>restrictedFields</em>, <em>restrictLinks</em>, <em>firewall</em></p>\n<p>This is for advanced usage and it completes the security of exposure. \nThis may be a bit tricky to understand at first because there are many rules, but don’t give up hope, it’s quite easy.</p>\n<blockquote class=\"pullquote warning\"><p>By using body, Grapher automatically assumes you have control over what you give, meaning all firewalls from other exposures for linked elements (if they exist) will be bypassed. But not the firewall of the current exposure.</p>\n</blockquote>\n<h3 id=\"Basic-Usage\"><a href=\"#Basic-Usage\" class=\"headerlink\" title=\"Basic Usage\"></a>Basic Usage</h3><figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div></pre></td><td class=\"code\"><pre><div class=\"line\">Collection.expose({</div><div class=\"line\"> <span class=\"attr\">body</span>: {</div><div class=\"line\"> <span class=\"attr\">firstName</span>: <span class=\"number\">1</span>,</div><div class=\"line\"> <span class=\"attr\">link</span>: {</div><div class=\"line\"> <span class=\"attr\">someField</span>: <span class=\"number\">1</span></div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\">})</div></pre></td></tr></table></figure>\n<p>If you query from the <em>client-side</em> something like:\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div></pre></td><td class=\"code\"><pre><div class=\"line\">createQuery({</div><div class=\"line\"> <span class=\"attr\">collection</span>: {</div><div class=\"line\"> <span class=\"attr\">firstName</span>: <span class=\"number\">1</span>,</div><div class=\"line\"> <span class=\"attr\">lastName</span>: <span class=\"number\">1</span>,</div><div class=\"line\"> <span class=\"attr\">link</span>: {</div><div class=\"line\"> <span class=\"attr\">someOtherField</span>: <span class=\"number\">1</span></div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\">})</div></pre></td></tr></table></figure></p>\n<p>The intersected body will look like:\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div></pre></td><td class=\"code\"><pre><div class=\"line\">{</div><div class=\"line\"> <span class=\"attr\">firstName</span>: <span class=\"number\">1</span>,</div><div class=\"line\"> <span class=\"attr\">link</span>: {}</div><div class=\"line\">}</div></pre></td></tr></table></figure></p>\n<p>Ok, but what if I want to have a different body based on the userId ? Body can also be a function that takes in an userId, and returns an object.</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div></pre></td><td class=\"code\"><pre><div class=\"line\">Collection.expose({</div><div class=\"line\"> body(userId) {</div><div class=\"line\"> <span class=\"keyword\">let</span> body = { <span class=\"attr\">firstName</span>: <span class=\"number\">1</span> };</div><div class=\"line\"> </div><div class=\"line\"> <span class=\"keyword\">if</span> (isAdmin(userId)) {</div><div class=\"line\"> _.extend(body, { <span class=\"attr\">lastName</span>: <span class=\"number\">1</span> })</div><div class=\"line\"> }</div><div class=\"line\"> </div><div class=\"line\"> <span class=\"keyword\">return</span> body;</div><div class=\"line\"> }</div><div class=\"line\">})</div></pre></td></tr></table></figure>\n<blockquote class=\"pullquote warning\"><p>Deep nesting with other links not be allowed unless your <em>body</em> specifies it.</p>\n</blockquote>\n<p>The special fields “$filters” and “$options” are allowed at any link level (including root). However, they will go through a phase of cleaning,\nmeaning it will only allow to filter and sort for fields that exist in the body.</p>\n<blockquote class=\"pullquote warning\"><p>We got your back covered!</p>\n<p>This check goes deeply to verify “$and”, “$or”, “$nin” and “$not” special MongoDB selectors. This way you are sure you do not expose data you don’t want to.\nBecause, given enough requests, a hacker playing with $filters and $sort options can figure out a field that you may not want to give him access to.</p>\n</blockquote>\n<p>If the <em>body</em> contains functions they will be computed before intersection. Each function will receive userId.\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div></pre></td><td class=\"code\"><pre><div class=\"line\">{</div><div class=\"line\"> linkName(userId) { <span class=\"keyword\">return</span> {<span class=\"attr\">test</span>: <span class=\"number\">1</span>} }</div><div class=\"line\">}</div><div class=\"line\"></div><div class=\"line\"><span class=\"comment\">// transforms into</span></div><div class=\"line\">{</div><div class=\"line\"> <span class=\"attr\">linkName</span>: {</div><div class=\"line\"> <span class=\"attr\">test</span>: <span class=\"number\">1</span></div><div class=\"line\"> }</div><div class=\"line\">}</div></pre></td></tr></table></figure></p>\n<p>You can return <em>undefined</em> or <em>false</em> in your function if you want to disable the field/link for intersection.</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div></pre></td><td class=\"code\"><pre><div class=\"line\">{</div><div class=\"line\"> linkName(userId) {</div><div class=\"line\"> <span class=\"keyword\">if</span> (isAdmin(userId)) {</div><div class=\"line\"> <span class=\"keyword\">return</span> object;</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\">}</div></pre></td></tr></table></figure>\n<h3 id=\"Linking-Grapher-Exposure-Bodies\"><a href=\"#Linking-Grapher-Exposure-Bodies\" class=\"headerlink\" title=\"Linking Grapher Exposure Bodies\"></a>Linking Grapher Exposure Bodies</h3><p>You can link bodies in your own way and also reference other bodies’links.\nFunctions are computed on-demand, meaning you can have self-referencing body functions:</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div><div class=\"line\">20</div><div class=\"line\">21</div><div class=\"line\">22</div><div class=\"line\">23</div><div class=\"line\">24</div><div class=\"line\">25</div><div class=\"line\">26</div><div class=\"line\">27</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">// Comments ONE link to Users as 'user' </span></div><div class=\"line\"><span class=\"comment\">// Users INVERSED 'user' from Comments AS 'comments'</span></div><div class=\"line\"></div><div class=\"line\"><span class=\"keyword\">const</span> commentBody = <span class=\"function\">(<span class=\"params\">userId</span>) =></span> {</div><div class=\"line\"> <span class=\"keyword\">return</span> {</div><div class=\"line\"> <span class=\"attr\">user</span>: userBody</div><div class=\"line\"> text: <span class=\"number\">1</span></div><div class=\"line\"> }</div><div class=\"line\">}</div><div class=\"line\"></div><div class=\"line\"><span class=\"keyword\">const</span> userBody = <span class=\"function\">(<span class=\"params\">userId</span>) =></span> {</div><div class=\"line\"> <span class=\"keyword\">if</span> (isAdmin(userId)) {</div><div class=\"line\"> <span class=\"keyword\">return</span> {</div><div class=\"line\"> <span class=\"attr\">comments</span>: commentBody</div><div class=\"line\"> }; </div><div class=\"line\"> }</div><div class=\"line\"> </div><div class=\"line\"> <span class=\"keyword\">return</span> somethingElse;</div><div class=\"line\">}</div><div class=\"line\"></div><div class=\"line\">Users.expose({</div><div class=\"line\"> <span class=\"attr\">body</span>: userBody</div><div class=\"line\">})</div><div class=\"line\"></div><div class=\"line\">Comments.expose({</div><div class=\"line\"> <span class=\"attr\">body</span>: commentBody</div><div class=\"line\">})</div></pre></td></tr></table></figure>\n<p>This will allow requests like:\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div></pre></td><td class=\"code\"><pre><div class=\"line\">{</div><div class=\"line\"> <span class=\"attr\">users</span>: {</div><div class=\"line\"> <span class=\"attr\">comments</span>: {</div><div class=\"line\"> <span class=\"attr\">user</span>: {</div><div class=\"line\"> <span class=\"comment\">// It doesn't make much sense for this case</span></div><div class=\"line\"> <span class=\"comment\">// but you can have </span></div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\">}</div></pre></td></tr></table></figure></p>\n","excerpt":"","more":"<h1 id=\"Collection-Exposure\"><a href=\"#Collection-Exposure\" class=\"headerlink\" title=\"Collection Exposure\"></a>Collection Exposure</h1><p>In order to query for a collection from the client-side and fetch it or subscribe to it. You must expose it.</p>\n<p>Exposing a collection does the following things:</p>\n<ul>\n<li>Creates a method called: exposure_{collectionName} which accepts a query</li>\n<li>Creates a publication called: exposure_{collectionName} which accepts a query and uses <a href=\"https://atmospherejs.com/reywood/publish-composite\">reywood:publish-composite</a> to achieve reactive relationships.</li>\n<li>If firewall is specified, it extends <em>find</em> method of your collection, allowing an extra parameter:<figure class=\"highlight gradle\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\">Collection.<span class=\"keyword\">find</span>(filters, <span class=\"keyword\">options</span>, userId);</div></pre></td></tr></table></figure>\n</li>\n</ul>\n<blockquote class=\"pullquote warning\"><p>If <em>userId</em> is undefined, the firewall and constraints will not be applied. If the <em>userId</em> is <em>null</em>, the firewall will be applied. This is to allow server-side fetching without any restrictions.</p>\n</blockquote>\n<h2 id=\"Exposing-a-collection-to-everyone\"><a href=\"#Exposing-a-collection-to-everyone\" class=\"headerlink\" title=\"Exposing a collection to everyone\"></a>Exposing a collection to everyone</h2><figure class=\"highlight coq\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">Collection</span>.expose()</div></pre></td></tr></table></figure>\n<h2 id=\"Exposing-a-collection-to-logged-in-users\"><a href=\"#Exposing-a-collection-to-logged-in-users\" class=\"headerlink\" title=\"Exposing a collection to logged in users\"></a>Exposing a collection to logged in users</h2><figure class=\"highlight gradle\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div></pre></td><td class=\"code\"><pre><div class=\"line\">Collection.expose({</div><div class=\"line\"> firewall(filters, <span class=\"keyword\">options</span>, userId) {</div><div class=\"line\"> <span class=\"keyword\">if</span> (!userId) {</div><div class=\"line\"> <span class=\"keyword\">throw</span> <span class=\"keyword\">new</span> Meteor.Error(<span class=\"string\">'...'</span>);</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\">});</div></pre></td></tr></table></figure>\n<h2 id=\"Enforcing-limits\"><a href=\"#Enforcing-limits\" class=\"headerlink\" title=\"Enforcing limits\"></a>Enforcing limits</h2><figure class=\"highlight gams\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div></pre></td><td class=\"code\"><pre><div class=\"line\">Collection.expose({</div><div class=\"line\"> firewall(filters, <span class=\"keyword\">options</span>, userId) {</div><div class=\"line\"> filters.userId = userId;</div><div class=\"line\"> }</div><div class=\"line\"> maxLimit: <span class=\"number\">100</span>, <span class=\"comment\">// The publication/method will not allow data fetching for more than 100 items. (Performance related)</span></div><div class=\"line\"> maxDepth: <span class=\"number\">3</span> <span class=\"comment\">// The publication/method will not allow a query with more than 3 levels deep. (Performance related)</span></div><div class=\"line\"> restrictedFields: [<span class=\"string\">'services'</span>, <span class=\"string\">'secretField'</span>] <span class=\"comment\">// this will clean up filters, options.sort and options.fields and remove those fields from there.</span></div><div class=\"line\">});</div></pre></td></tr></table></figure>\n<h2 id=\"Exposure-firewalls-are-linked\"><a href=\"#Exposure-firewalls-are-linked\" class=\"headerlink\" title=\"Exposure firewalls are linked.\"></a>Exposure firewalls are linked.</h2><p>When querying for a data-graph like:\n<figure class=\"highlight css\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div></pre></td><td class=\"code\"><pre><div class=\"line\">{</div><div class=\"line\"> <span class=\"attribute\">users</span>: {</div><div class=\"line\"> comments: {}</div><div class=\"line\"> }</div><div class=\"line\">}</div></pre></td></tr></table></figure></p>\n<p>It is not necessary to have an exposure for <em>comments</em>, however if you do have it, and it has a firewall. The firewall will be called.\nThe reason for this is security.</p>\n<blockquote class=\"pullquote warning\"><p>Don’t worry about performance. We went great lengths to retrieve data in as few MongoDB requests as possible, in the scenario above,\nif you do have a firewall for users and comments, both will be called only once, because we only make 2 MongoDB requests.</p>\n</blockquote>\n<h2 id=\"Global-Exposure-Configuration\"><a href=\"#Global-Exposure-Configuration\" class=\"headerlink\" title=\"Global Exposure Configuration\"></a>Global Exposure Configuration</h2><figure class=\"highlight javascript\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">import</span> { Exposure } <span class=\"keyword\">from</span> <span class=\"string\">'meteor/cultofcoders:grapher'</span>;</div><div class=\"line\"></div><div class=\"line\"><span class=\"comment\">// Make sure you do this before exposing any collections.</span></div><div class=\"line\">Exposure.setConfig({</div><div class=\"line\"> firewall,</div><div class=\"line\"> maxLimit,</div><div class=\"line\"> maxDepth,</div><div class=\"line\"> restrictFields</div><div class=\"line\">});</div></pre></td></tr></table></figure>\n<p>When you expose a collection, it will extend the global exposure methods.\nThe reason for this is you may want a global limit of 100, or you may want a maximum graph depth of 5 for all your exposed collections,\nwithout having to specify this for each.</p>\n<p>Important: if global exposure has a firewall and the collection exposure has a firewall defined as welll, the collection exposure firewall will be applied. </p>\n<h2 id=\"Taming-The-Firewall\"><a href=\"#Taming-The-Firewall\" class=\"headerlink\" title=\"Taming The Firewall\"></a>Taming The Firewall</h2><figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">// control what to show</span></div><div class=\"line\"></div><div class=\"line\">Collection.expose({</div><div class=\"line\"> firewall(filters, options, userId) => {</div><div class=\"line\"> <span class=\"keyword\">if</span> (!isAdmin(userId)) {</div><div class=\"line\"> filters.isVisible = <span class=\"literal\">true</span>;</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\">});</div></pre></td></tr></table></figure>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">// make certain fields invisible for certain users</span></div><div class=\"line\"><span class=\"keyword\">import</span> { Exposure } <span class=\"keyword\">from</span> <span class=\"string\">'meteor/cultofcoders:grapher'</span></div><div class=\"line\">Collection.expose({</div><div class=\"line\"> firewall(filters, options, userId) => {</div><div class=\"line\"> <span class=\"keyword\">if</span> (!isAdmin(userId)) {</div><div class=\"line\"> Exposure.restrictFields(filters, options, [<span class=\"string\">'privateData'</span>])</div><div class=\"line\"> <span class=\"comment\">// it will remove all specified fields from filters, options.sort, options.fields</span></div><div class=\"line\"> <span class=\"comment\">// this way you will not expose unwanted data.</span></div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\">});</div></pre></td></tr></table></figure>\n<h2 id=\"Restricting-Links\"><a href=\"#Restricting-Links\" class=\"headerlink\" title=\"Restricting Links\"></a>Restricting Links</h2><p>Restrict using a simple array:\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div></pre></td><td class=\"code\"><pre><div class=\"line\">Collection.expose({</div><div class=\"line\"> <span class=\"attr\">restrictLinks</span>: [<span class=\"string\">'privateLink'</span>, <span class=\"string\">'anotherPrivateLink'</span>]</div><div class=\"line\">});</div></pre></td></tr></table></figure></p>\n<p>Compute restricted links when fetching the query:\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div></pre></td><td class=\"code\"><pre><div class=\"line\">Collection.expose({</div><div class=\"line\"> restrictLinks(userId) {</div><div class=\"line\"> <span class=\"keyword\">return</span> [<span class=\"string\">'privateLink'</span>, <span class=\"string\">'anotherPrivateLink'</span>]</div><div class=\"line\"> }</div><div class=\"line\">});</div></pre></td></tr></table></figure></p>\n<h2 id=\"Exposure-Body\"><a href=\"#Exposure-Body\" class=\"headerlink\" title=\"Exposure Body\"></a>Exposure Body</h2><p>Creating an exposure body basically states that:\n“I allow the client to request anything he wants from what I allow him to.”</p>\n<p>If <em>body</em> is specified, it is first applied on the request and then the subsequent rules such as <em>restrictedFields</em>, <em>restrictLinks</em>, <em>firewall</em></p>\n<p>This is for advanced usage and it completes the security of exposure. \nThis may be a bit tricky to understand at first because there are many rules, but don’t give up hope, it’s quite easy.</p>\n<blockquote class=\"pullquote warning\"><p>By using body, Grapher automatically assumes you have control over what you give, meaning all firewalls from other exposures for linked elements (if they exist) will be bypassed. But not the firewall of the current exposure.</p>\n</blockquote>\n<h3 id=\"Basic-Usage\"><a href=\"#Basic-Usage\" class=\"headerlink\" title=\"Basic Usage\"></a>Basic Usage</h3><figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div></pre></td><td class=\"code\"><pre><div class=\"line\">Collection.expose({</div><div class=\"line\"> <span class=\"attr\">body</span>: {</div><div class=\"line\"> <span class=\"attr\">firstName</span>: <span class=\"number\">1</span>,</div><div class=\"line\"> <span class=\"attr\">link</span>: {</div><div class=\"line\"> <span class=\"attr\">someField</span>: <span class=\"number\">1</span></div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\">})</div></pre></td></tr></table></figure>\n<p>If you query from the <em>client-side</em> something like:\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div></pre></td><td class=\"code\"><pre><div class=\"line\">createQuery({</div><div class=\"line\"> <span class=\"attr\">collection</span>: {</div><div class=\"line\"> <span class=\"attr\">firstName</span>: <span class=\"number\">1</span>,</div><div class=\"line\"> <span class=\"attr\">lastName</span>: <span class=\"number\">1</span>,</div><div class=\"line\"> <span class=\"attr\">link</span>: {</div><div class=\"line\"> <span class=\"attr\">someOtherField</span>: <span class=\"number\">1</span></div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\">})</div></pre></td></tr></table></figure></p>\n<p>The intersected body will look like:\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div></pre></td><td class=\"code\"><pre><div class=\"line\">{</div><div class=\"line\"> <span class=\"attr\">firstName</span>: <span class=\"number\">1</span>,</div><div class=\"line\"> <span class=\"attr\">link</span>: {}</div><div class=\"line\">}</div></pre></td></tr></table></figure></p>\n<p>Ok, but what if I want to have a different body based on the userId ? Body can also be a function that takes in an userId, and returns an object.</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div></pre></td><td class=\"code\"><pre><div class=\"line\">Collection.expose({</div><div class=\"line\"> body(userId) {</div><div class=\"line\"> <span class=\"keyword\">let</span> body = { <span class=\"attr\">firstName</span>: <span class=\"number\">1</span> };</div><div class=\"line\"> </div><div class=\"line\"> <span class=\"keyword\">if</span> (isAdmin(userId)) {</div><div class=\"line\"> _.extend(body, { <span class=\"attr\">lastName</span>: <span class=\"number\">1</span> })</div><div class=\"line\"> }</div><div class=\"line\"> </div><div class=\"line\"> <span class=\"keyword\">return</span> body;</div><div class=\"line\"> }</div><div class=\"line\">})</div></pre></td></tr></table></figure>\n<blockquote class=\"pullquote warning\"><p>Deep nesting with other links not be allowed unless your <em>body</em> specifies it.</p>\n</blockquote>\n<p>The special fields “$filters” and “$options” are allowed at any link level (including root). However, they will go through a phase of cleaning,\nmeaning it will only allow to filter and sort for fields that exist in the body.</p>\n<blockquote class=\"pullquote warning\"><p>We got your back covered!</p>\n<p>This check goes deeply to verify “$and”, “$or”, “$nin” and “$not” special MongoDB selectors. This way you are sure you do not expose data you don’t want to.\nBecause, given enough requests, a hacker playing with $filters and $sort options can figure out a field that you may not want to give him access to.</p>\n</blockquote>\n<p>If the <em>body</em> contains functions they will be computed before intersection. Each function will receive userId.\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div></pre></td><td class=\"code\"><pre><div class=\"line\">{</div><div class=\"line\"> linkName(userId) { <span class=\"keyword\">return</span> {<span class=\"attr\">test</span>: <span class=\"number\">1</span>} }</div><div class=\"line\">}</div><div class=\"line\"></div><div class=\"line\"><span class=\"comment\">// transforms into</span></div><div class=\"line\">{</div><div class=\"line\"> <span class=\"attr\">linkName</span>: {</div><div class=\"line\"> <span class=\"attr\">test</span>: <span class=\"number\">1</span></div><div class=\"line\"> }</div><div class=\"line\">}</div></pre></td></tr></table></figure></p>\n<p>You can return <em>undefined</em> or <em>false</em> in your function if you want to disable the field/link for intersection.</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div></pre></td><td class=\"code\"><pre><div class=\"line\">{</div><div class=\"line\"> linkName(userId) {</div><div class=\"line\"> <span class=\"keyword\">if</span> (isAdmin(userId)) {</div><div class=\"line\"> <span class=\"keyword\">return</span> object;</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\">}</div></pre></td></tr></table></figure>\n<h3 id=\"Linking-Grapher-Exposure-Bodies\"><a href=\"#Linking-Grapher-Exposure-Bodies\" class=\"headerlink\" title=\"Linking Grapher Exposure Bodies\"></a>Linking Grapher Exposure Bodies</h3><p>You can link bodies in your own way and also reference other bodies’links.\nFunctions are computed on-demand, meaning you can have self-referencing body functions:</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div><div class=\"line\">20</div><div class=\"line\">21</div><div class=\"line\">22</div><div class=\"line\">23</div><div class=\"line\">24</div><div class=\"line\">25</div><div class=\"line\">26</div><div class=\"line\">27</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">// Comments ONE link to Users as 'user' </span></div><div class=\"line\"><span class=\"comment\">// Users INVERSED 'user' from Comments AS 'comments'</span></div><div class=\"line\"></div><div class=\"line\"><span class=\"keyword\">const</span> commentBody = <span class=\"function\">(<span class=\"params\">userId</span>) =></span> {</div><div class=\"line\"> <span class=\"keyword\">return</span> {</div><div class=\"line\"> <span class=\"attr\">user</span>: userBody</div><div class=\"line\"> text: <span class=\"number\">1</span></div><div class=\"line\"> }</div><div class=\"line\">}</div><div class=\"line\"></div><div class=\"line\"><span class=\"keyword\">const</span> userBody = <span class=\"function\">(<span class=\"params\">userId</span>) =></span> {</div><div class=\"line\"> <span class=\"keyword\">if</span> (isAdmin(userId)) {</div><div class=\"line\"> <span class=\"keyword\">return</span> {</div><div class=\"line\"> <span class=\"attr\">comments</span>: commentBody</div><div class=\"line\"> }; </div><div class=\"line\"> }</div><div class=\"line\"> </div><div class=\"line\"> <span class=\"keyword\">return</span> somethingElse;</div><div class=\"line\">}</div><div class=\"line\"></div><div class=\"line\">Users.expose({</div><div class=\"line\"> <span class=\"attr\">body</span>: userBody</div><div class=\"line\">})</div><div class=\"line\"></div><div class=\"line\">Comments.expose({</div><div class=\"line\"> <span class=\"attr\">body</span>: commentBody</div><div class=\"line\">})</div></pre></td></tr></table></figure>\n<p>This will allow requests like:\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div></pre></td><td class=\"code\"><pre><div class=\"line\">{</div><div class=\"line\"> <span class=\"attr\">users</span>: {</div><div class=\"line\"> <span class=\"attr\">comments</span>: {</div><div class=\"line\"> <span class=\"attr\">user</span>: {</div><div class=\"line\"> <span class=\"comment\">// It doesn't make much sense for this case</span></div><div class=\"line\"> <span class=\"comment\">// but you can have </span></div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\">}</div></pre></td></tr></table></figure></p>\n"},{"title":"Exposure","description":"Reference API for Grapher Exposure","_content":"\nExposure is used to allow a certain collection as an *Entry Point* for your query. Exposing is done server side.\n\n{% pullquote 'warning' %}\nNamedQuery is not affected by exposure at all. It has it's own firewall.\n{% endpullquote %}\n\n## Exposure.setConfig\nThis is for global configuration. It will apply to all exposures unless overriden.\n\n```js\nimport { Exposure } from 'meteor/cultofcoders:grapher';\n\nExposure.setConfig({\n firewall(filters, options, userId) {}, \n maxLimit, // integer value, force a maximum limit to results\n maxDepth, // integer value, allow the data graph to a certain depth\n publication, // allow reactivity (dynamic queries)\n method, // allow fetching via method (static queries)\n});\n```\n\n## Collection.expose()\n\nIf you specify any parameters used in the global configuration, they will be overridden.\n\n```js\nCollection.expose({\n firewall(filters, options, userId) {\n },\n maxLimit,\n maxDepth,\n restrictedFields: [], // array of fields you want to restrict\n method: true, // allow it via method\n publication: true, // allow it via \n restrictLinks, // function(userId) that returns array, or array,\n body, // object that will intersect with the actual request body from the client\n});\n```\n\n## Collection.find()\n\nIf you have exposed your Collection and provided a firewall. Then the find() method will be extended, allowing an additional userId field.\n\n```js\nCollection.find(filters, options, userId)\n```\n\n{% pullquote 'warning' %}\nIf *userId* is undefined. Firewall will not be called and applied. Use *null* or *false* for non-logged-in users.\n{% endpullquote %}\n\n## Exposure.restrictFields()\n\nRestrict certain fields, and remove them from filters and options deeply and securely.\nIt will even clean-out filters with $and, $or, $nor, $not. \n\n```js\nimport { Exposure } from 'meteor/cultofcoders:grapher';\n\nUsers.expose({\n firewall(filters, options, userId) {\n Exposure.restrictFields(filters, options, ['services'])\n }\n});\n```\n\n## Firewalls are linked\n\n{% pullquote 'warning' %}\nIf you specify a body to your exposures, in that case firewalls will not be linked, they will be bypassed.\n{% endpullquote %}\n\n```js\n{\n posts: {\n title: 1,\n comments: {\n text: 1\n }\n }\n}\n```\n\nIf *comments*'s collection is exposed. The firewall of comments will be applied.\n\nExample:\n\n```js\nPosts.expose();\nComments.expose({\n firewall(filters, options, userId) {\n filters.userId = userId;\n }\n})\n```\n\nThen this query:\n\n```js\n{\n posts: {\n comments: {}\n }\n}\n```\n\nWill only return posts and comments for which userId is the current logged in user.\n\nWhen exposure rules become too complex, the best solution is to use [Named Query](/api/namedQuery.html)","source":"api/exposure.md","raw":"---\ntitle: Exposure\ndescription: Reference API for Grapher Exposure\n---\n\nExposure is used to allow a certain collection as an *Entry Point* for your query. Exposing is done server side.\n\n{% pullquote 'warning' %}\nNamedQuery is not affected by exposure at all. It has it's own firewall.\n{% endpullquote %}\n\n## Exposure.setConfig\nThis is for global configuration. It will apply to all exposures unless overriden.\n\n```js\nimport { Exposure } from 'meteor/cultofcoders:grapher';\n\nExposure.setConfig({\n firewall(filters, options, userId) {}, \n maxLimit, // integer value, force a maximum limit to results\n maxDepth, // integer value, allow the data graph to a certain depth\n publication, // allow reactivity (dynamic queries)\n method, // allow fetching via method (static queries)\n});\n```\n\n## Collection.expose()\n\nIf you specify any parameters used in the global configuration, they will be overridden.\n\n```js\nCollection.expose({\n firewall(filters, options, userId) {\n },\n maxLimit,\n maxDepth,\n restrictedFields: [], // array of fields you want to restrict\n method: true, // allow it via method\n publication: true, // allow it via \n restrictLinks, // function(userId) that returns array, or array,\n body, // object that will intersect with the actual request body from the client\n});\n```\n\n## Collection.find()\n\nIf you have exposed your Collection and provided a firewall. Then the find() method will be extended, allowing an additional userId field.\n\n```js\nCollection.find(filters, options, userId)\n```\n\n{% pullquote 'warning' %}\nIf *userId* is undefined. Firewall will not be called and applied. Use *null* or *false* for non-logged-in users.\n{% endpullquote %}\n\n## Exposure.restrictFields()\n\nRestrict certain fields, and remove them from filters and options deeply and securely.\nIt will even clean-out filters with $and, $or, $nor, $not. \n\n```js\nimport { Exposure } from 'meteor/cultofcoders:grapher';\n\nUsers.expose({\n firewall(filters, options, userId) {\n Exposure.restrictFields(filters, options, ['services'])\n }\n});\n```\n\n## Firewalls are linked\n\n{% pullquote 'warning' %}\nIf you specify a body to your exposures, in that case firewalls will not be linked, they will be bypassed.\n{% endpullquote %}\n\n```js\n{\n posts: {\n title: 1,\n comments: {\n text: 1\n }\n }\n}\n```\n\nIf *comments*'s collection is exposed. The firewall of comments will be applied.\n\nExample:\n\n```js\nPosts.expose();\nComments.expose({\n firewall(filters, options, userId) {\n filters.userId = userId;\n }\n})\n```\n\nThen this query:\n\n```js\n{\n posts: {\n comments: {}\n }\n}\n```\n\nWill only return posts and comments for which userId is the current logged in user.\n\nWhen exposure rules become too complex, the best solution is to use [Named Query](/api/namedQuery.html)","date":"2016-11-21T12:17:34.299Z","updated":"2016-11-21T12:17:34.299Z","path":"api/exposure.html","_id":"ciu5gd5su00008sjxdoz63j11","comments":1,"layout":"page","content":"<p>Exposure is used to allow a certain collection as an <em>Entry Point</em> for your query. Exposing is done server side.</p>\n<blockquote class=\"pullquote warning\"><p>NamedQuery is not affected by exposure at all. It has it’s own firewall.</p>\n</blockquote>\n<h2 id=\"Exposure-setConfig\"><a href=\"#Exposure-setConfig\" class=\"headerlink\" title=\"Exposure.setConfig\"></a>Exposure.setConfig</h2><p>This is for global configuration. It will apply to all exposures unless overriden.</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">import</span> { Exposure } <span class=\"keyword\">from</span> <span class=\"string\">'meteor/cultofcoders:grapher'</span>;</div><div class=\"line\"></div><div class=\"line\">Exposure.setConfig({</div><div class=\"line\"> firewall(filters, options, userId) {}, </div><div class=\"line\"> maxLimit, <span class=\"comment\">// integer value, force a maximum limit to results</span></div><div class=\"line\"> maxDepth, <span class=\"comment\">// integer value, allow the data graph to a certain depth</span></div><div class=\"line\"> publication, <span class=\"comment\">// allow reactivity (dynamic queries)</span></div><div class=\"line\"> method, <span class=\"comment\">// allow fetching via method (static queries)</span></div><div class=\"line\">});</div></pre></td></tr></table></figure>\n<h2 id=\"Collection-expose\"><a href=\"#Collection-expose\" class=\"headerlink\" title=\"Collection.expose()\"></a>Collection.expose()</h2><p>If you specify any parameters used in the global configuration, they will be overridden.</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div></pre></td><td class=\"code\"><pre><div class=\"line\">Collection.expose({</div><div class=\"line\"> firewall(filters, options, userId) {</div><div class=\"line\"> },</div><div class=\"line\"> maxLimit,</div><div class=\"line\"> maxDepth,</div><div class=\"line\"> <span class=\"attr\">restrictedFields</span>: [], <span class=\"comment\">// array of fields you want to restrict</span></div><div class=\"line\"> method: <span class=\"literal\">true</span>, <span class=\"comment\">// allow it via method</span></div><div class=\"line\"> publication: <span class=\"literal\">true</span>, <span class=\"comment\">// allow it via </span></div><div class=\"line\"> restrictLinks, <span class=\"comment\">// function(userId) that returns array, or array,</span></div><div class=\"line\"> body, <span class=\"comment\">// object that will intersect with the actual request body from the client</span></div><div class=\"line\">});</div></pre></td></tr></table></figure>\n<h2 id=\"Collection-find\"><a href=\"#Collection-find\" class=\"headerlink\" title=\"Collection.find()\"></a>Collection.find()</h2><p>If you have exposed your Collection and provided a firewall. Then the find() method will be extended, allowing an additional userId field.</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\">Collection.find(filters, options, userId)</div></pre></td></tr></table></figure>\n<blockquote class=\"pullquote warning\"><p>If <em>userId</em> is undefined. Firewall will not be called and applied. Use <em>null</em> or <em>false</em> for non-logged-in users.</p>\n</blockquote>\n<h2 id=\"Exposure-restrictFields\"><a href=\"#Exposure-restrictFields\" class=\"headerlink\" title=\"Exposure.restrictFields()\"></a>Exposure.restrictFields()</h2><p>Restrict certain fields, and remove them from filters and options deeply and securely.\nIt will even clean-out filters with $and, $or, $nor, $not. </p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">import</span> { Exposure } <span class=\"keyword\">from</span> <span class=\"string\">'meteor/cultofcoders:grapher'</span>;</div><div class=\"line\"></div><div class=\"line\">Users.expose({</div><div class=\"line\"> firewall(filters, options, userId) {</div><div class=\"line\"> Exposure.restrictFields(filters, options, [<span class=\"string\">'services'</span>])</div><div class=\"line\"> }</div><div class=\"line\">});</div></pre></td></tr></table></figure>\n<h2 id=\"Firewalls-are-linked\"><a href=\"#Firewalls-are-linked\" class=\"headerlink\" title=\"Firewalls are linked\"></a>Firewalls are linked</h2><blockquote class=\"pullquote warning\"><p>If you specify a body to your exposures, in that case firewalls will not be linked, they will be bypassed.</p>\n</blockquote>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div></pre></td><td class=\"code\"><pre><div class=\"line\">{</div><div class=\"line\"> <span class=\"attr\">posts</span>: {</div><div class=\"line\"> <span class=\"attr\">title</span>: <span class=\"number\">1</span>,</div><div class=\"line\"> <span class=\"attr\">comments</span>: {</div><div class=\"line\"> <span class=\"attr\">text</span>: <span class=\"number\">1</span></div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\">}</div></pre></td></tr></table></figure>\n<p>If <em>comments</em>‘s collection is exposed. The firewall of comments will be applied.</p>\n<p>Example:</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div></pre></td><td class=\"code\"><pre><div class=\"line\">Posts.expose();</div><div class=\"line\">Comments.expose({</div><div class=\"line\"> firewall(filters, options, userId) {</div><div class=\"line\"> filters.userId = userId;</div><div class=\"line\"> }</div><div class=\"line\">})</div></pre></td></tr></table></figure>\n<p>Then this query:</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div></pre></td><td class=\"code\"><pre><div class=\"line\">{</div><div class=\"line\"> <span class=\"attr\">posts</span>: {</div><div class=\"line\"> <span class=\"attr\">comments</span>: {}</div><div class=\"line\"> }</div><div class=\"line\">}</div></pre></td></tr></table></figure>\n<p>Will only return posts and comments for which userId is the current logged in user.</p>\n<p>When exposure rules become too complex, the best solution is to use <a href=\"/api/namedQuery.html\">Named Query</a></p>\n","excerpt":"","more":"<p>Exposure is used to allow a certain collection as an <em>Entry Point</em> for your query. Exposing is done server side.</p>\n<blockquote class=\"pullquote warning\"><p>NamedQuery is not affected by exposure at all. It has it’s own firewall.</p>\n</blockquote>\n<h2 id=\"Exposure-setConfig\"><a href=\"#Exposure-setConfig\" class=\"headerlink\" title=\"Exposure.setConfig\"></a>Exposure.setConfig</h2><p>This is for global configuration. It will apply to all exposures unless overriden.</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">import</span> { Exposure } <span class=\"keyword\">from</span> <span class=\"string\">'meteor/cultofcoders:grapher'</span>;</div><div class=\"line\"></div><div class=\"line\">Exposure.setConfig({</div><div class=\"line\"> firewall(filters, options, userId) {}, </div><div class=\"line\"> maxLimit, <span class=\"comment\">// integer value, force a maximum limit to results</span></div><div class=\"line\"> maxDepth, <span class=\"comment\">// integer value, allow the data graph to a certain depth</span></div><div class=\"line\"> publication, <span class=\"comment\">// allow reactivity (dynamic queries)</span></div><div class=\"line\"> method, <span class=\"comment\">// allow fetching via method (static queries)</span></div><div class=\"line\">});</div></pre></td></tr></table></figure>\n<h2 id=\"Collection-expose\"><a href=\"#Collection-expose\" class=\"headerlink\" title=\"Collection.expose()\"></a>Collection.expose()</h2><p>If you specify any parameters used in the global configuration, they will be overridden.</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div></pre></td><td class=\"code\"><pre><div class=\"line\">Collection.expose({</div><div class=\"line\"> firewall(filters, options, userId) {</div><div class=\"line\"> },</div><div class=\"line\"> maxLimit,</div><div class=\"line\"> maxDepth,</div><div class=\"line\"> <span class=\"attr\">restrictedFields</span>: [], <span class=\"comment\">// array of fields you want to restrict</span></div><div class=\"line\"> method: <span class=\"literal\">true</span>, <span class=\"comment\">// allow it via method</span></div><div class=\"line\"> publication: <span class=\"literal\">true</span>, <span class=\"comment\">// allow it via </span></div><div class=\"line\"> restrictLinks, <span class=\"comment\">// function(userId) that returns array, or array,</span></div><div class=\"line\"> body, <span class=\"comment\">// object that will intersect with the actual request body from the client</span></div><div class=\"line\">});</div></pre></td></tr></table></figure>\n<h2 id=\"Collection-find\"><a href=\"#Collection-find\" class=\"headerlink\" title=\"Collection.find()\"></a>Collection.find()</h2><p>If you have exposed your Collection and provided a firewall. Then the find() method will be extended, allowing an additional userId field.</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\">Collection.find(filters, options, userId)</div></pre></td></tr></table></figure>\n<blockquote class=\"pullquote warning\"><p>If <em>userId</em> is undefined. Firewall will not be called and applied. Use <em>null</em> or <em>false</em> for non-logged-in users.</p>\n</blockquote>\n<h2 id=\"Exposure-restrictFields\"><a href=\"#Exposure-restrictFields\" class=\"headerlink\" title=\"Exposure.restrictFields()\"></a>Exposure.restrictFields()</h2><p>Restrict certain fields, and remove them from filters and options deeply and securely.\nIt will even clean-out filters with $and, $or, $nor, $not. </p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">import</span> { Exposure } <span class=\"keyword\">from</span> <span class=\"string\">'meteor/cultofcoders:grapher'</span>;</div><div class=\"line\"></div><div class=\"line\">Users.expose({</div><div class=\"line\"> firewall(filters, options, userId) {</div><div class=\"line\"> Exposure.restrictFields(filters, options, [<span class=\"string\">'services'</span>])</div><div class=\"line\"> }</div><div class=\"line\">});</div></pre></td></tr></table></figure>\n<h2 id=\"Firewalls-are-linked\"><a href=\"#Firewalls-are-linked\" class=\"headerlink\" title=\"Firewalls are linked\"></a>Firewalls are linked</h2><blockquote class=\"pullquote warning\"><p>If you specify a body to your exposures, in that case firewalls will not be linked, they will be bypassed.</p>\n</blockquote>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div></pre></td><td class=\"code\"><pre><div class=\"line\">{</div><div class=\"line\"> <span class=\"attr\">posts</span>: {</div><div class=\"line\"> <span class=\"attr\">title</span>: <span class=\"number\">1</span>,</div><div class=\"line\"> <span class=\"attr\">comments</span>: {</div><div class=\"line\"> <span class=\"attr\">text</span>: <span class=\"number\">1</span></div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\">}</div></pre></td></tr></table></figure>\n<p>If <em>comments</em>‘s collection is exposed. The firewall of comments will be applied.</p>\n<p>Example:</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div></pre></td><td class=\"code\"><pre><div class=\"line\">Posts.expose();</div><div class=\"line\">Comments.expose({</div><div class=\"line\"> firewall(filters, options, userId) {</div><div class=\"line\"> filters.userId = userId;</div><div class=\"line\"> }</div><div class=\"line\">})</div></pre></td></tr></table></figure>\n<p>Then this query:</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div></pre></td><td class=\"code\"><pre><div class=\"line\">{</div><div class=\"line\"> <span class=\"attr\">posts</span>: {</div><div class=\"line\"> <span class=\"attr\">comments</span>: {}</div><div class=\"line\"> }</div><div class=\"line\">}</div></pre></td></tr></table></figure>\n<p>Will only return posts and comments for which userId is the current logged in user.</p>\n<p>When exposure rules become too complex, the best solution is to use <a href=\"/api/namedQuery.html\">Named Query</a></p>\n"},{"title":"Named Query","description":"Reference API for Grapher Named Query","_content":"\n{% pullquote 'warning' %}\nNamedQuery is not affected by exposure at all. It has it's own firewall.\n{% endpullquote %}\n\n## createNamedQuery()\n\n```js\nimport { createNamedQuery } from 'meteor/cultofcoders:grapher';\n\nconst query = createNamedQuery('postList', {\n posts: {\n title: 1,\n comments: {\n text: 1\n }\n }\n});\n```\n\n*query* has the same API as Query. [Check it out here](/api/query.html)\n\n## NamedQuery.expose(config)\n\nServer-side only. This is used for giving access to a named query client-side.\n\n```js\nquery.expose({\n firewall(userId, params) {\n // throw-out an exception or do anything you want\n },\n method: true, // defaults to true, allows you to fetch it statically\n publication: true, // defaults to true, allows you to fetch it reactively,\n embody: {\n // deep merges with the query body after the first node\n // this allows you to have full control over the query without exposing important business logic to the client\n teamMember: {\n $filters: {isActive: true}\n }\n }\n})\n```\n\n## Basic usage\n\n```js\n// client-side\nimport postList from '/imports/api/posts/queries/postList.js';\n\npostList.clone(params).fetch((err, data) => {\n // do something with data\n})\n// server-side\nimport postList from '/imports/api/posts/queries/postList.js';\n\npostList.clone(params).fetch()\n```\n\n## createQuery()\n\n{% pullquote 'warning' %}\nIf you use *createQuery*, your query must be already loaded for the client. Imported in your startup file, or however you do. The reason is that\nonce a *NamedQuery* is registered, it is kept in a store. And when using *createQuery()* it will try to interogate that store.\n\nThe only reason we allow this, instead of importing it, is to allow testing it live with [Grapher-Live package](https://github.com/cult-of-coders/grapher-live)\n{% endpullquote %}\n\n```js\nimport { createQuery } from 'meteor/cultofcoders:grapher';\n\nconst query = createQuery({\n postList: {\n text: 'Hello World!' // in this case the body of postList are actually the parameters.\n }\n})\n```\n\n*query* has the same API as Query. [Check it out here](/api/query.html)\n","source":"api/namedQuery.md","raw":"---\ntitle: Named Query\ndescription: Reference API for Grapher Named Query\n---\n\n{% pullquote 'warning' %}\nNamedQuery is not affected by exposure at all. It has it's own firewall.\n{% endpullquote %}\n\n## createNamedQuery()\n\n```js\nimport { createNamedQuery } from 'meteor/cultofcoders:grapher';\n\nconst query = createNamedQuery('postList', {\n posts: {\n title: 1,\n comments: {\n text: 1\n }\n }\n});\n```\n\n*query* has the same API as Query. [Check it out here](/api/query.html)\n\n## NamedQuery.expose(config)\n\nServer-side only. This is used for giving access to a named query client-side.\n\n```js\nquery.expose({\n firewall(userId, params) {\n // throw-out an exception or do anything you want\n },\n method: true, // defaults to true, allows you to fetch it statically\n publication: true, // defaults to true, allows you to fetch it reactively,\n embody: {\n // deep merges with the query body after the first node\n // this allows you to have full control over the query without exposing important business logic to the client\n teamMember: {\n $filters: {isActive: true}\n }\n }\n})\n```\n\n## Basic usage\n\n```js\n// client-side\nimport postList from '/imports/api/posts/queries/postList.js';\n\npostList.clone(params).fetch((err, data) => {\n // do something with data\n})\n// server-side\nimport postList from '/imports/api/posts/queries/postList.js';\n\npostList.clone(params).fetch()\n```\n\n## createQuery()\n\n{% pullquote 'warning' %}\nIf you use *createQuery*, your query must be already loaded for the client. Imported in your startup file, or however you do. The reason is that\nonce a *NamedQuery* is registered, it is kept in a store. And when using *createQuery()* it will try to interogate that store.\n\nThe only reason we allow this, instead of importing it, is to allow testing it live with [Grapher-Live package](https://github.com/cult-of-coders/grapher-live)\n{% endpullquote %}\n\n```js\nimport { createQuery } from 'meteor/cultofcoders:grapher';\n\nconst query = createQuery({\n postList: {\n text: 'Hello World!' // in this case the body of postList are actually the parameters.\n }\n})\n```\n\n*query* has the same API as Query. [Check it out here](/api/query.html)\n","date":"2016-11-21T12:18:02.267Z","updated":"2016-11-21T12:18:02.267Z","path":"api/namedQuery.html","_id":"ciu5gd5ta00018sjx83igh0le","comments":1,"layout":"page","content":"<blockquote class=\"pullquote warning\"><p>NamedQuery is not affected by exposure at all. It has it’s own firewall.</p>\n</blockquote>\n<h2 id=\"createNamedQuery\"><a href=\"#createNamedQuery\" class=\"headerlink\" title=\"createNamedQuery()\"></a>createNamedQuery()</h2><figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">import</span> { createNamedQuery } <span class=\"keyword\">from</span> <span class=\"string\">'meteor/cultofcoders:grapher'</span>;</div><div class=\"line\"></div><div class=\"line\"><span class=\"keyword\">const</span> query = createNamedQuery(<span class=\"string\">'postList'</span>, {</div><div class=\"line\"> <span class=\"attr\">posts</span>: {</div><div class=\"line\"> <span class=\"attr\">title</span>: <span class=\"number\">1</span>,</div><div class=\"line\"> <span class=\"attr\">comments</span>: {</div><div class=\"line\"> <span class=\"attr\">text</span>: <span class=\"number\">1</span></div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\">});</div></pre></td></tr></table></figure>\n<p><em>query</em> has the same API as Query. <a href=\"/api/query.html\">Check it out here</a></p>\n<h2 id=\"NamedQuery-expose-config\"><a href=\"#NamedQuery-expose-config\" class=\"headerlink\" title=\"NamedQuery.expose(config)\"></a>NamedQuery.expose(config)</h2><p>Server-side only. This is used for giving access to a named query client-side.</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div></pre></td><td class=\"code\"><pre><div class=\"line\">query.expose({</div><div class=\"line\"> firewall(userId, params) {</div><div class=\"line\"> <span class=\"comment\">// throw-out an exception or do anything you want</span></div><div class=\"line\"> },</div><div class=\"line\"> <span class=\"attr\">method</span>: <span class=\"literal\">true</span>, <span class=\"comment\">// defaults to true, allows you to fetch it statically</span></div><div class=\"line\"> publication: <span class=\"literal\">true</span>, <span class=\"comment\">// defaults to true, allows you to fetch it reactively,</span></div><div class=\"line\"> embody: {</div><div class=\"line\"> <span class=\"comment\">// deep merges with the query body after the first node</span></div><div class=\"line\"> <span class=\"comment\">// this allows you to have full control over the query without exposing important business logic to the client</span></div><div class=\"line\"> teamMember: {</div><div class=\"line\"> <span class=\"attr\">$filters</span>: {<span class=\"attr\">isActive</span>: <span class=\"literal\">true</span>}</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\">})</div></pre></td></tr></table></figure>\n<h2 id=\"Basic-usage\"><a href=\"#Basic-usage\" class=\"headerlink\" title=\"Basic usage\"></a>Basic usage</h2><figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">// client-side</span></div><div class=\"line\"><span class=\"keyword\">import</span> postList <span class=\"keyword\">from</span> <span class=\"string\">'/imports/api/posts/queries/postList.js'</span>;</div><div class=\"line\"></div><div class=\"line\">postList.clone(params).fetch(<span class=\"function\">(<span class=\"params\">err, data</span>) =></span> {</div><div class=\"line\"> <span class=\"comment\">// do something with data</span></div><div class=\"line\">})</div><div class=\"line\"><span class=\"comment\">// server-side</span></div><div class=\"line\"><span class=\"keyword\">import</span> postList <span class=\"keyword\">from</span> <span class=\"string\">'/imports/api/posts/queries/postList.js'</span>;</div><div class=\"line\"></div><div class=\"line\">postList.clone(params).fetch()</div></pre></td></tr></table></figure>\n<h2 id=\"createQuery\"><a href=\"#createQuery\" class=\"headerlink\" title=\"createQuery()\"></a>createQuery()</h2><blockquote class=\"pullquote warning\"><p>If you use <em>createQuery</em>, your query must be already loaded for the client. Imported in your startup file, or however you do. The reason is that\nonce a <em>NamedQuery</em> is registered, it is kept in a store. And when using <em>createQuery()</em> it will try to interogate that store.</p>\n<p>The only reason we allow this, instead of importing it, is to allow testing it live with <a href=\"https://github.com/cult-of-coders/grapher-live\" target=\"_blank\" rel=\"external\">Grapher-Live package</a></p>\n</blockquote>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">import</span> { createQuery } <span class=\"keyword\">from</span> <span class=\"string\">'meteor/cultofcoders:grapher'</span>;</div><div class=\"line\"></div><div class=\"line\"><span class=\"keyword\">const</span> query = createQuery({</div><div class=\"line\"> <span class=\"attr\">postList</span>: {</div><div class=\"line\"> <span class=\"attr\">text</span>: <span class=\"string\">'Hello World!'</span> <span class=\"comment\">// in this case the body of postList are actually the parameters.</span></div><div class=\"line\"> }</div><div class=\"line\">})</div></pre></td></tr></table></figure>\n<p><em>query</em> has the same API as Query. <a href=\"/api/query.html\">Check it out here</a></p>\n","excerpt":"","more":"<blockquote class=\"pullquote warning\"><p>NamedQuery is not affected by exposure at all. It has it’s own firewall.</p>\n</blockquote>\n<h2 id=\"createNamedQuery\"><a href=\"#createNamedQuery\" class=\"headerlink\" title=\"createNamedQuery()\"></a>createNamedQuery()</h2><figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">import</span> { createNamedQuery } <span class=\"keyword\">from</span> <span class=\"string\">'meteor/cultofcoders:grapher'</span>;</div><div class=\"line\"></div><div class=\"line\"><span class=\"keyword\">const</span> query = createNamedQuery(<span class=\"string\">'postList'</span>, {</div><div class=\"line\"> <span class=\"attr\">posts</span>: {</div><div class=\"line\"> <span class=\"attr\">title</span>: <span class=\"number\">1</span>,</div><div class=\"line\"> <span class=\"attr\">comments</span>: {</div><div class=\"line\"> <span class=\"attr\">text</span>: <span class=\"number\">1</span></div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\">});</div></pre></td></tr></table></figure>\n<p><em>query</em> has the same API as Query. <a href=\"/api/query.html\">Check it out here</a></p>\n<h2 id=\"NamedQuery-expose-config\"><a href=\"#NamedQuery-expose-config\" class=\"headerlink\" title=\"NamedQuery.expose(config)\"></a>NamedQuery.expose(config)</h2><p>Server-side only. This is used for giving access to a named query client-side.</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div></pre></td><td class=\"code\"><pre><div class=\"line\">query.expose({</div><div class=\"line\"> firewall(userId, params) {</div><div class=\"line\"> <span class=\"comment\">// throw-out an exception or do anything you want</span></div><div class=\"line\"> },</div><div class=\"line\"> <span class=\"attr\">method</span>: <span class=\"literal\">true</span>, <span class=\"comment\">// defaults to true, allows you to fetch it statically</span></div><div class=\"line\"> publication: <span class=\"literal\">true</span>, <span class=\"comment\">// defaults to true, allows you to fetch it reactively,</span></div><div class=\"line\"> embody: {</div><div class=\"line\"> <span class=\"comment\">// deep merges with the query body after the first node</span></div><div class=\"line\"> <span class=\"comment\">// this allows you to have full control over the query without exposing important business logic to the client</span></div><div class=\"line\"> teamMember: {</div><div class=\"line\"> <span class=\"attr\">$filters</span>: {<span class=\"attr\">isActive</span>: <span class=\"literal\">true</span>}</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\">})</div></pre></td></tr></table></figure>\n<h2 id=\"Basic-usage\"><a href=\"#Basic-usage\" class=\"headerlink\" title=\"Basic usage\"></a>Basic usage</h2><figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">// client-side</span></div><div class=\"line\"><span class=\"keyword\">import</span> postList <span class=\"keyword\">from</span> <span class=\"string\">'/imports/api/posts/queries/postList.js'</span>;</div><div class=\"line\"></div><div class=\"line\">postList.clone(params).fetch(<span class=\"function\">(<span class=\"params\">err, data</span>) =></span> {</div><div class=\"line\"> <span class=\"comment\">// do something with data</span></div><div class=\"line\">})</div><div class=\"line\"><span class=\"comment\">// server-side</span></div><div class=\"line\"><span class=\"keyword\">import</span> postList <span class=\"keyword\">from</span> <span class=\"string\">'/imports/api/posts/queries/postList.js'</span>;</div><div class=\"line\"></div><div class=\"line\">postList.clone(params).fetch()</div></pre></td></tr></table></figure>\n<h2 id=\"createQuery\"><a href=\"#createQuery\" class=\"headerlink\" title=\"createQuery()\"></a>createQuery()</h2><blockquote class=\"pullquote warning\"><p>If you use <em>createQuery</em>, your query must be already loaded for the client. Imported in your startup file, or however you do. The reason is that\nonce a <em>NamedQuery</em> is registered, it is kept in a store. And when using <em>createQuery()</em> it will try to interogate that store.</p>\n<p>The only reason we allow this, instead of importing it, is to allow testing it live with <a href=\"https://github.com/cult-of-coders/grapher-live\">Grapher-Live package</a></p>\n</blockquote>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">import</span> { createQuery } <span class=\"keyword\">from</span> <span class=\"string\">'meteor/cultofcoders:grapher'</span>;</div><div class=\"line\"></div><div class=\"line\"><span class=\"keyword\">const</span> query = createQuery({</div><div class=\"line\"> <span class=\"attr\">postList</span>: {</div><div class=\"line\"> <span class=\"attr\">text</span>: <span class=\"string\">'Hello World!'</span> <span class=\"comment\">// in this case the body of postList are actually the parameters.</span></div><div class=\"line\"> }</div><div class=\"line\">})</div></pre></td></tr></table></figure>\n<p><em>query</em> has the same API as Query. <a href=\"/api/query.html\">Check it out here</a></p>\n"},{"title":"Linking","description":"Reference API for Grapher Links","_content":"\n## Adding Direct Links\n\n```js\nPosts = new Mongo.Collection('posts');\nComments = new Mongo.Collection('comments');\n\nComments.addLinks({\n post: {\n type: 'one'|'many',\n collection: Posts,\n field: 'postId' // optional, it generates a unique one\n metadata: {} // optional, use it for meta relationships\n index: false // optional, if set to true will create indexes for the links\n autoremove: false // if set to true it will remove the linked objects from database\n unique: false // optional, if you want a one-to-one kind of relationship \n }\n});\n```\n\n## Adding Inversed Links\n\n```js\nPosts.addLinks({\n comments: {\n collection: Comments,\n inversedBy: 'post' // the name of the link in Comments\n // for inversed links these are the only options allowed\n }\n});\n```\n\n## Adding Resolver Links\n\n```js\nPosts.addLinks({\n commentsCount: {\n resolve(post) {\n // here you can put any sync call, like a REST API call\n return Posts.getLink(post, 'comments').find().count();\n }\n }\n});\n```\n\n## Fetching Links\n\n```js\nconst postCommentsLink = Posts.getLink(postId, 'comments');\nconst commentPostLink = Comments.getLink(commentId, 'post');\n\ncommentPostLink.fetch(); // retrieves a single post object\ncommentPostLink.find().fetch(); // retrieves an array with one element called object.\n\npostCommentsLink.fetch(); // retrieves all linked comments\npostCommentsLink.find().fetch(); // retrieves all linked comments\n```\n\n\n{% pullquote 'warning' %}\n*getLink* also accepts objects that contain an *_id*: Collection.getLink(post, 'comments')\n{% endpullquote %}\n\nWhen fetching the links you can specify additional filters and options:\n```js\npostCommentsLink.find(filters, options).fetch(); // retrieves linked comments with specific filters and options\npostCommentsLink.fetch(filters, options); // retrieves linked comments with specific filters and options\n```\n\n{% pullquote 'warning' %}\nlink.fetch() is smarter than link.find().fetch() because it may return a single result or array of results, depending on the type.\n{% endpullquote %}\n\n## Managing Links\n\n{% pullquote 'warning' %}\nWhen adding, removing links. Please not that the arguments acceptable are smart meaning you can provide:\n\n- Single Object With *_id*\n- String *_id* \n- Single Object without *_id* (It will also create it in the database)\n- Array of Single Objects with *_id*\n- Array of *_id*\n- Array with any mixture: [objectWithId, objectWithoutId, _id]\n{% endpullquote %}\n\n{% pullquote 'warning' %}\nWhen removing links, you must have objects or *_id* strings, otherwise it wouldn't make sense.\n{% endpullquote %}\n\n## Managing Links (One Relationship)\n\n```js\n// for one relationships\nlink.set(relatedId);\nlink.unset();\n```\n\n\n## Managing Links (One Meta Relationship)\n\n```js\nlink.set(relatedId, {isSomething: true});\nlink.metadata(); // returns the metadata: // {_id: relatedId, isSomething: true}\nlink.metadata({isSomething: false}); // sets the metadata by extending the current metadata.\nlink.metadata({otherStuff: true}); // will update the metadata\nlink.metadata(); // returns the metadata: {_id: relatedId, someConditions: true, otherStuff: true}\nlink.unset(); // removes the link along with metadata.\n```\n\n## Managing Links (Many Relationship)\n\n```js\nlink.add(relatedId) // accepts as arguments: [relatedId1, relatedId2], relatedObject, [relatedObject1, relatedObject2]\nlink.add(objectWithoutIdProperty) // it will create the object and save it in the db and also link it\nlink.add([objectWithoutIdProperty, _id]) // it will create the object objectWithoutIdProperty and link it, and it will just link it with _id string\n\nlink.remove(relatedId) // accepts as arguments: [relatedId1, relatedId2], relatedObject, [relatedObject1, relatedObject2]\n```\n\n## Managing Links (Many Meta Relationship)\n\n```js\nlink.add(relatedId, {someConditions: true}); // it also works with [relatedId1, relatedId2, relatedObj1, relatedObj2]\nlink.metadata(relatedId) // {_id: relatedId, someConditions: true}\nlink.metadata() // [{_id: relatedId, someConditions: true}, {_id: relatedI2, someThingElse: false}, ...]\nlink.metadata(relatedId, {otherStuff: true}); // will update the metadata\nlink.metadata(relatedId) // {_id: relatedId, someConditions: true, otherStuff: true}\nlink.remove(relatedId); // will remove the link with the relatedId along with the metadata\n```\n\n## Managing Links - Inversed\n\nThis is an inversed link because the storage is stored in *Comments* collection.\n\n{% pullquote 'warning' %}\nWhen managing links from inversed side you are allowed to use set(), unset(), add(), remove(), \nto be able to use it in a natural language. postCommentsLink.set(commentId) wouldn't make much sense in this case.\n{% endpullquote %}\n\n```js\npostCommentsLink = Posts.getLink(postId, 'comments');\n\npostCommentsLink.add(commentWithoutId) // will create a comment object in database and link it to post\npostCommentsLink.add(arrayOfCommentsWithorWithoutIds) // for those without id it will create them and link them, for the others it will just link them\n\npostCommentsLink.remove(commentWithId) // it will remove the links\npostCommentsLink.remove(_id) // it will remove the links\n```","source":"api/links.md","raw":"---\ntitle: Linking\ndescription: Reference API for Grapher Links\n---\n\n## Adding Direct Links\n\n```js\nPosts = new Mongo.Collection('posts');\nComments = new Mongo.Collection('comments');\n\nComments.addLinks({\n post: {\n type: 'one'|'many',\n collection: Posts,\n field: 'postId' // optional, it generates a unique one\n metadata: {} // optional, use it for meta relationships\n index: false // optional, if set to true will create indexes for the links\n autoremove: false // if set to true it will remove the linked objects from database\n unique: false // optional, if you want a one-to-one kind of relationship \n }\n});\n```\n\n## Adding Inversed Links\n\n```js\nPosts.addLinks({\n comments: {\n collection: Comments,\n inversedBy: 'post' // the name of the link in Comments\n // for inversed links these are the only options allowed\n }\n});\n```\n\n## Adding Resolver Links\n\n```js\nPosts.addLinks({\n commentsCount: {\n resolve(post) {\n // here you can put any sync call, like a REST API call\n return Posts.getLink(post, 'comments').find().count();\n }\n }\n});\n```\n\n## Fetching Links\n\n```js\nconst postCommentsLink = Posts.getLink(postId, 'comments');\nconst commentPostLink = Comments.getLink(commentId, 'post');\n\ncommentPostLink.fetch(); // retrieves a single post object\ncommentPostLink.find().fetch(); // retrieves an array with one element called object.\n\npostCommentsLink.fetch(); // retrieves all linked comments\npostCommentsLink.find().fetch(); // retrieves all linked comments\n```\n\n\n{% pullquote 'warning' %}\n*getLink* also accepts objects that contain an *_id*: Collection.getLink(post, 'comments')\n{% endpullquote %}\n\nWhen fetching the links you can specify additional filters and options:\n```js\npostCommentsLink.find(filters, options).fetch(); // retrieves linked comments with specific filters and options\npostCommentsLink.fetch(filters, options); // retrieves linked comments with specific filters and options\n```\n\n{% pullquote 'warning' %}\nlink.fetch() is smarter than link.find().fetch() because it may return a single result or array of results, depending on the type.\n{% endpullquote %}\n\n## Managing Links\n\n{% pullquote 'warning' %}\nWhen adding, removing links. Please not that the arguments acceptable are smart meaning you can provide:\n\n- Single Object With *_id*\n- String *_id* \n- Single Object without *_id* (It will also create it in the database)\n- Array of Single Objects with *_id*\n- Array of *_id*\n- Array with any mixture: [objectWithId, objectWithoutId, _id]\n{% endpullquote %}\n\n{% pullquote 'warning' %}\nWhen removing links, you must have objects or *_id* strings, otherwise it wouldn't make sense.\n{% endpullquote %}\n\n## Managing Links (One Relationship)\n\n```js\n// for one relationships\nlink.set(relatedId);\nlink.unset();\n```\n\n\n## Managing Links (One Meta Relationship)\n\n```js\nlink.set(relatedId, {isSomething: true});\nlink.metadata(); // returns the metadata: // {_id: relatedId, isSomething: true}\nlink.metadata({isSomething: false}); // sets the metadata by extending the current metadata.\nlink.metadata({otherStuff: true}); // will update the metadata\nlink.metadata(); // returns the metadata: {_id: relatedId, someConditions: true, otherStuff: true}\nlink.unset(); // removes the link along with metadata.\n```\n\n## Managing Links (Many Relationship)\n\n```js\nlink.add(relatedId) // accepts as arguments: [relatedId1, relatedId2], relatedObject, [relatedObject1, relatedObject2]\nlink.add(objectWithoutIdProperty) // it will create the object and save it in the db and also link it\nlink.add([objectWithoutIdProperty, _id]) // it will create the object objectWithoutIdProperty and link it, and it will just link it with _id string\n\nlink.remove(relatedId) // accepts as arguments: [relatedId1, relatedId2], relatedObject, [relatedObject1, relatedObject2]\n```\n\n## Managing Links (Many Meta Relationship)\n\n```js\nlink.add(relatedId, {someConditions: true}); // it also works with [relatedId1, relatedId2, relatedObj1, relatedObj2]\nlink.metadata(relatedId) // {_id: relatedId, someConditions: true}\nlink.metadata() // [{_id: relatedId, someConditions: true}, {_id: relatedI2, someThingElse: false}, ...]\nlink.metadata(relatedId, {otherStuff: true}); // will update the metadata\nlink.metadata(relatedId) // {_id: relatedId, someConditions: true, otherStuff: true}\nlink.remove(relatedId); // will remove the link with the relatedId along with the metadata\n```\n\n## Managing Links - Inversed\n\nThis is an inversed link because the storage is stored in *Comments* collection.\n\n{% pullquote 'warning' %}\nWhen managing links from inversed side you are allowed to use set(), unset(), add(), remove(), \nto be able to use it in a natural language. postCommentsLink.set(commentId) wouldn't make much sense in this case.\n{% endpullquote %}\n\n```js\npostCommentsLink = Posts.getLink(postId, 'comments');\n\npostCommentsLink.add(commentWithoutId) // will create a comment object in database and link it to post\npostCommentsLink.add(arrayOfCommentsWithorWithoutIds) // for those without id it will create them and link them, for the others it will just link them\n\npostCommentsLink.remove(commentWithId) // it will remove the links\npostCommentsLink.remove(_id) // it will remove the links\n```","date":"2016-11-21T12:17:51.883Z","updated":"2016-11-21T12:17:51.883Z","path":"api/links.html","_id":"ciu5gd5ta00028sjxssibikht","comments":1,"layout":"page","content":"<h2 id=\"Adding-Direct-Links\"><a href=\"#Adding-Direct-Links\" class=\"headerlink\" title=\"Adding Direct Links\"></a>Adding Direct Links</h2><figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div></pre></td><td class=\"code\"><pre><div class=\"line\">Posts = <span class=\"keyword\">new</span> Mongo.Collection(<span class=\"string\">'posts'</span>);</div><div class=\"line\">Comments = <span class=\"keyword\">new</span> Mongo.Collection(<span class=\"string\">'comments'</span>);</div><div class=\"line\"></div><div class=\"line\">Comments.addLinks({</div><div class=\"line\"> <span class=\"attr\">post</span>: {</div><div class=\"line\"> <span class=\"attr\">type</span>: <span class=\"string\">'one'</span>|<span class=\"string\">'many'</span>,</div><div class=\"line\"> <span class=\"attr\">collection</span>: Posts,</div><div class=\"line\"> <span class=\"attr\">field</span>: <span class=\"string\">'postId'</span> <span class=\"comment\">// optional, it generates a unique one</span></div><div class=\"line\"> metadata: {} <span class=\"comment\">// optional, use it for meta relationships</span></div><div class=\"line\"> index: <span class=\"literal\">false</span> <span class=\"comment\">// optional, if set to true will create indexes for the links</span></div><div class=\"line\"> autoremove: <span class=\"literal\">false</span> <span class=\"comment\">// if set to true it will remove the linked objects from database</span></div><div class=\"line\"> unique: <span class=\"literal\">false</span> <span class=\"comment\">// optional, if you want a one-to-one kind of relationship </span></div><div class=\"line\"> }</div><div class=\"line\">});</div></pre></td></tr></table></figure>\n<h2 id=\"Adding-Inversed-Links\"><a href=\"#Adding-Inversed-Links\" class=\"headerlink\" title=\"Adding Inversed Links\"></a>Adding Inversed Links</h2><figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div></pre></td><td class=\"code\"><pre><div class=\"line\">Posts.addLinks({</div><div class=\"line\"> <span class=\"attr\">comments</span>: {</div><div class=\"line\"> <span class=\"attr\">collection</span>: Comments,</div><div class=\"line\"> <span class=\"attr\">inversedBy</span>: <span class=\"string\">'post'</span> <span class=\"comment\">// the name of the link in Comments</span></div><div class=\"line\"> <span class=\"comment\">// for inversed links these are the only options allowed</span></div><div class=\"line\"> }</div><div class=\"line\">});</div></pre></td></tr></table></figure>\n<h2 id=\"Adding-Resolver-Links\"><a href=\"#Adding-Resolver-Links\" class=\"headerlink\" title=\"Adding Resolver Links\"></a>Adding Resolver Links</h2><figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div></pre></td><td class=\"code\"><pre><div class=\"line\">Posts.addLinks({</div><div class=\"line\"> <span class=\"attr\">commentsCount</span>: {</div><div class=\"line\"> resolve(post) {</div><div class=\"line\"> <span class=\"comment\">// here you can put any sync call, like a REST API call</span></div><div class=\"line\"> <span class=\"keyword\">return</span> Posts.getLink(post, <span class=\"string\">'comments'</span>).find().count();</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\">});</div></pre></td></tr></table></figure>\n<h2 id=\"Fetching-Links\"><a href=\"#Fetching-Links\" class=\"headerlink\" title=\"Fetching Links\"></a>Fetching Links</h2><figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">const</span> postCommentsLink = Posts.getLink(postId, <span class=\"string\">'comments'</span>);</div><div class=\"line\"><span class=\"keyword\">const</span> commentPostLink = Comments.getLink(commentId, <span class=\"string\">'post'</span>);</div><div class=\"line\"></div><div class=\"line\">commentPostLink.fetch(); <span class=\"comment\">// retrieves a single post object</span></div><div class=\"line\">commentPostLink.find().fetch(); <span class=\"comment\">// retrieves an array with one element called object.</span></div><div class=\"line\"></div><div class=\"line\">postCommentsLink.fetch(); <span class=\"comment\">// retrieves all linked comments</span></div><div class=\"line\">postCommentsLink.find().fetch(); <span class=\"comment\">// retrieves all linked comments</span></div></pre></td></tr></table></figure>\n<blockquote class=\"pullquote warning\"><p><em>getLink</em> also accepts objects that contain an <em>_id</em>: Collection.getLink(post, ‘comments’)</p>\n</blockquote>\n<p>When fetching the links you can specify additional filters and options:\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div></pre></td><td class=\"code\"><pre><div class=\"line\">postCommentsLink.find(filters, options).fetch(); <span class=\"comment\">// retrieves linked comments with specific filters and options</span></div><div class=\"line\">postCommentsLink.fetch(filters, options); <span class=\"comment\">// retrieves linked comments with specific filters and options</span></div></pre></td></tr></table></figure></p>\n<blockquote class=\"pullquote warning\"><p>link.fetch() is smarter than link.find().fetch() because it may return a single result or array of results, depending on the type.</p>\n</blockquote>\n<h2 id=\"Managing-Links\"><a href=\"#Managing-Links\" class=\"headerlink\" title=\"Managing Links\"></a>Managing Links</h2><blockquote class=\"pullquote warning\"><p>When adding, removing links. Please not that the arguments acceptable are smart meaning you can provide:</p>\n<ul>\n<li>Single Object With <em>_id</em></li>\n<li>String <em>_id</em> </li>\n<li>Single Object without <em>_id</em> (It will also create it in the database)</li>\n<li>Array of Single Objects with <em>_id</em></li>\n<li>Array of <em>_id</em></li>\n<li>Array with any mixture: [objectWithId, objectWithoutId, _id]</li>\n</ul>\n</blockquote>\n<blockquote class=\"pullquote warning\"><p>When removing links, you must have objects or <em>_id</em> strings, otherwise it wouldn’t make sense.</p>\n</blockquote>\n<h2 id=\"Managing-Links-One-Relationship\"><a href=\"#Managing-Links-One-Relationship\" class=\"headerlink\" title=\"Managing Links (One Relationship)\"></a>Managing Links (One Relationship)</h2><figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">// for one relationships</span></div><div class=\"line\">link.set(relatedId);</div><div class=\"line\">link.unset();</div></pre></td></tr></table></figure>\n<h2 id=\"Managing-Links-One-Meta-Relationship\"><a href=\"#Managing-Links-One-Meta-Relationship\" class=\"headerlink\" title=\"Managing Links (One Meta Relationship)\"></a>Managing Links (One Meta Relationship)</h2><figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div></pre></td><td class=\"code\"><pre><div class=\"line\">link.set(relatedId, {<span class=\"attr\">isSomething</span>: <span class=\"literal\">true</span>});</div><div class=\"line\">link.metadata(); <span class=\"comment\">// returns the metadata: // {_id: relatedId, isSomething: true}</span></div><div class=\"line\">link.metadata({<span class=\"attr\">isSomething</span>: <span class=\"literal\">false</span>}); <span class=\"comment\">// sets the metadata by extending the current metadata.</span></div><div class=\"line\">link.metadata({<span class=\"attr\">otherStuff</span>: <span class=\"literal\">true</span>}); <span class=\"comment\">// will update the metadata</span></div><div class=\"line\">link.metadata(); <span class=\"comment\">// returns the metadata: {_id: relatedId, someConditions: true, otherStuff: true}</span></div><div class=\"line\">link.unset(); <span class=\"comment\">// removes the link along with metadata.</span></div></pre></td></tr></table></figure>\n<h2 id=\"Managing-Links-Many-Relationship\"><a href=\"#Managing-Links-Many-Relationship\" class=\"headerlink\" title=\"Managing Links (Many Relationship)\"></a>Managing Links (Many Relationship)</h2><figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div></pre></td><td class=\"code\"><pre><div class=\"line\">link.add(relatedId) <span class=\"comment\">// accepts as arguments: [relatedId1, relatedId2], relatedObject, [relatedObject1, relatedObject2]</span></div><div class=\"line\">link.add(objectWithoutIdProperty) <span class=\"comment\">// it will create the object and save it in the db and also link it</span></div><div class=\"line\">link.add([objectWithoutIdProperty, _id]) <span class=\"comment\">// it will create the object objectWithoutIdProperty and link it, and it will just link it with _id string</span></div><div class=\"line\"></div><div class=\"line\">link.remove(relatedId) <span class=\"comment\">// accepts as arguments: [relatedId1, relatedId2], relatedObject, [relatedObject1, relatedObject2]</span></div></pre></td></tr></table></figure>\n<h2 id=\"Managing-Links-Many-Meta-Relationship\"><a href=\"#Managing-Links-Many-Meta-Relationship\" class=\"headerlink\" title=\"Managing Links (Many Meta Relationship)\"></a>Managing Links (Many Meta Relationship)</h2><figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div></pre></td><td class=\"code\"><pre><div class=\"line\">link.add(relatedId, {<span class=\"attr\">someConditions</span>: <span class=\"literal\">true</span>}); <span class=\"comment\">// it also works with [relatedId1, relatedId2, relatedObj1, relatedObj2]</span></div><div class=\"line\">link.metadata(relatedId) <span class=\"comment\">// {_id: relatedId, someConditions: true}</span></div><div class=\"line\">link.metadata() <span class=\"comment\">// [{_id: relatedId, someConditions: true}, {_id: relatedI2, someThingElse: false}, ...]</span></div><div class=\"line\">link.metadata(relatedId, {<span class=\"attr\">otherStuff</span>: <span class=\"literal\">true</span>}); <span class=\"comment\">// will update the metadata</span></div><div class=\"line\">link.metadata(relatedId) <span class=\"comment\">// {_id: relatedId, someConditions: true, otherStuff: true}</span></div><div class=\"line\">link.remove(relatedId); <span class=\"comment\">// will remove the link with the relatedId along with the metadata</span></div></pre></td></tr></table></figure>\n<h2 id=\"Managing-Links-Inversed\"><a href=\"#Managing-Links-Inversed\" class=\"headerlink\" title=\"Managing Links - Inversed\"></a>Managing Links - Inversed</h2><p>This is an inversed link because the storage is stored in <em>Comments</em> collection.</p>\n<blockquote class=\"pullquote warning\"><p>When managing links from inversed side you are allowed to use set(), unset(), add(), remove(), \nto be able to use it in a natural language. postCommentsLink.set(commentId) wouldn’t make much sense in this case.</p>\n</blockquote>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div></pre></td><td class=\"code\"><pre><div class=\"line\">postCommentsLink = Posts.getLink(postId, <span class=\"string\">'comments'</span>);</div><div class=\"line\"></div><div class=\"line\">postCommentsLink.add(commentWithoutId) <span class=\"comment\">// will create a comment object in database and link it to post</span></div><div class=\"line\">postCommentsLink.add(arrayOfCommentsWithorWithoutIds) <span class=\"comment\">// for those without id it will create them and link them, for the others it will just link them</span></div><div class=\"line\"></div><div class=\"line\">postCommentsLink.remove(commentWithId) <span class=\"comment\">// it will remove the links</span></div><div class=\"line\">postCommentsLink.remove(_id) <span class=\"comment\">// it will remove the links</span></div></pre></td></tr></table></figure>","excerpt":"","more":"<h2 id=\"Adding-Direct-Links\"><a href=\"#Adding-Direct-Links\" class=\"headerlink\" title=\"Adding Direct Links\"></a>Adding Direct Links</h2><figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div></pre></td><td class=\"code\"><pre><div class=\"line\">Posts = <span class=\"keyword\">new</span> Mongo.Collection(<span class=\"string\">'posts'</span>);</div><div class=\"line\">Comments = <span class=\"keyword\">new</span> Mongo.Collection(<span class=\"string\">'comments'</span>);</div><div class=\"line\"></div><div class=\"line\">Comments.addLinks({</div><div class=\"line\"> <span class=\"attr\">post</span>: {</div><div class=\"line\"> <span class=\"attr\">type</span>: <span class=\"string\">'one'</span>|<span class=\"string\">'many'</span>,</div><div class=\"line\"> <span class=\"attr\">collection</span>: Posts,</div><div class=\"line\"> <span class=\"attr\">field</span>: <span class=\"string\">'postId'</span> <span class=\"comment\">// optional, it generates a unique one</span></div><div class=\"line\"> metadata: {} <span class=\"comment\">// optional, use it for meta relationships</span></div><div class=\"line\"> index: <span class=\"literal\">false</span> <span class=\"comment\">// optional, if set to true will create indexes for the links</span></div><div class=\"line\"> autoremove: <span class=\"literal\">false</span> <span class=\"comment\">// if set to true it will remove the linked objects from database</span></div><div class=\"line\"> unique: <span class=\"literal\">false</span> <span class=\"comment\">// optional, if you want a one-to-one kind of relationship </span></div><div class=\"line\"> }</div><div class=\"line\">});</div></pre></td></tr></table></figure>\n<h2 id=\"Adding-Inversed-Links\"><a href=\"#Adding-Inversed-Links\" class=\"headerlink\" title=\"Adding Inversed Links\"></a>Adding Inversed Links</h2><figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div></pre></td><td class=\"code\"><pre><div class=\"line\">Posts.addLinks({</div><div class=\"line\"> <span class=\"attr\">comments</span>: {</div><div class=\"line\"> <span class=\"attr\">collection</span>: Comments,</div><div class=\"line\"> <span class=\"attr\">inversedBy</span>: <span class=\"string\">'post'</span> <span class=\"comment\">// the name of the link in Comments</span></div><div class=\"line\"> <span class=\"comment\">// for inversed links these are the only options allowed</span></div><div class=\"line\"> }</div><div class=\"line\">});</div></pre></td></tr></table></figure>\n<h2 id=\"Adding-Resolver-Links\"><a href=\"#Adding-Resolver-Links\" class=\"headerlink\" title=\"Adding Resolver Links\"></a>Adding Resolver Links</h2><figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div></pre></td><td class=\"code\"><pre><div class=\"line\">Posts.addLinks({</div><div class=\"line\"> <span class=\"attr\">commentsCount</span>: {</div><div class=\"line\"> resolve(post) {</div><div class=\"line\"> <span class=\"comment\">// here you can put any sync call, like a REST API call</span></div><div class=\"line\"> <span class=\"keyword\">return</span> Posts.getLink(post, <span class=\"string\">'comments'</span>).find().count();</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\">});</div></pre></td></tr></table></figure>\n<h2 id=\"Fetching-Links\"><a href=\"#Fetching-Links\" class=\"headerlink\" title=\"Fetching Links\"></a>Fetching Links</h2><figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">const</span> postCommentsLink = Posts.getLink(postId, <span class=\"string\">'comments'</span>);</div><div class=\"line\"><span class=\"keyword\">const</span> commentPostLink = Comments.getLink(commentId, <span class=\"string\">'post'</span>);</div><div class=\"line\"></div><div class=\"line\">commentPostLink.fetch(); <span class=\"comment\">// retrieves a single post object</span></div><div class=\"line\">commentPostLink.find().fetch(); <span class=\"comment\">// retrieves an array with one element called object.</span></div><div class=\"line\"></div><div class=\"line\">postCommentsLink.fetch(); <span class=\"comment\">// retrieves all linked comments</span></div><div class=\"line\">postCommentsLink.find().fetch(); <span class=\"comment\">// retrieves all linked comments</span></div></pre></td></tr></table></figure>\n<blockquote class=\"pullquote warning\"><p><em>getLink</em> also accepts objects that contain an <em>_id</em>: Collection.getLink(post, ‘comments’)</p>\n</blockquote>\n<p>When fetching the links you can specify additional filters and options:\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div></pre></td><td class=\"code\"><pre><div class=\"line\">postCommentsLink.find(filters, options).fetch(); <span class=\"comment\">// retrieves linked comments with specific filters and options</span></div><div class=\"line\">postCommentsLink.fetch(filters, options); <span class=\"comment\">// retrieves linked comments with specific filters and options</span></div></pre></td></tr></table></figure></p>\n<blockquote class=\"pullquote warning\"><p>link.fetch() is smarter than link.find().fetch() because it may return a single result or array of results, depending on the type.</p>\n</blockquote>\n<h2 id=\"Managing-Links\"><a href=\"#Managing-Links\" class=\"headerlink\" title=\"Managing Links\"></a>Managing Links</h2><blockquote class=\"pullquote warning\"><p>When adding, removing links. Please not that the arguments acceptable are smart meaning you can provide:</p>\n<ul>\n<li>Single Object With <em>_id</em></li>\n<li>String <em>_id</em> </li>\n<li>Single Object without <em>_id</em> (It will also create it in the database)</li>\n<li>Array of Single Objects with <em>_id</em></li>\n<li>Array of <em>_id</em></li>\n<li>Array with any mixture: [objectWithId, objectWithoutId, _id]</li>\n</ul>\n</blockquote>\n<blockquote class=\"pullquote warning\"><p>When removing links, you must have objects or <em>_id</em> strings, otherwise it wouldn’t make sense.</p>\n</blockquote>\n<h2 id=\"Managing-Links-One-Relationship\"><a href=\"#Managing-Links-One-Relationship\" class=\"headerlink\" title=\"Managing Links (One Relationship)\"></a>Managing Links (One Relationship)</h2><figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">// for one relationships</span></div><div class=\"line\">link.set(relatedId);</div><div class=\"line\">link.unset();</div></pre></td></tr></table></figure>\n<h2 id=\"Managing-Links-One-Meta-Relationship\"><a href=\"#Managing-Links-One-Meta-Relationship\" class=\"headerlink\" title=\"Managing Links (One Meta Relationship)\"></a>Managing Links (One Meta Relationship)</h2><figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div></pre></td><td class=\"code\"><pre><div class=\"line\">link.set(relatedId, {<span class=\"attr\">isSomething</span>: <span class=\"literal\">true</span>});</div><div class=\"line\">link.metadata(); <span class=\"comment\">// returns the metadata: // {_id: relatedId, isSomething: true}</span></div><div class=\"line\">link.metadata({<span class=\"attr\">isSomething</span>: <span class=\"literal\">false</span>}); <span class=\"comment\">// sets the metadata by extending the current metadata.</span></div><div class=\"line\">link.metadata({<span class=\"attr\">otherStuff</span>: <span class=\"literal\">true</span>}); <span class=\"comment\">// will update the metadata</span></div><div class=\"line\">link.metadata(); <span class=\"comment\">// returns the metadata: {_id: relatedId, someConditions: true, otherStuff: true}</span></div><div class=\"line\">link.unset(); <span class=\"comment\">// removes the link along with metadata.</span></div></pre></td></tr></table></figure>\n<h2 id=\"Managing-Links-Many-Relationship\"><a href=\"#Managing-Links-Many-Relationship\" class=\"headerlink\" title=\"Managing Links (Many Relationship)\"></a>Managing Links (Many Relationship)</h2><figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div></pre></td><td class=\"code\"><pre><div class=\"line\">link.add(relatedId) <span class=\"comment\">// accepts as arguments: [relatedId1, relatedId2], relatedObject, [relatedObject1, relatedObject2]</span></div><div class=\"line\">link.add(objectWithoutIdProperty) <span class=\"comment\">// it will create the object and save it in the db and also link it</span></div><div class=\"line\">link.add([objectWithoutIdProperty, _id]) <span class=\"comment\">// it will create the object objectWithoutIdProperty and link it, and it will just link it with _id string</span></div><div class=\"line\"></div><div class=\"line\">link.remove(relatedId) <span class=\"comment\">// accepts as arguments: [relatedId1, relatedId2], relatedObject, [relatedObject1, relatedObject2]</span></div></pre></td></tr></table></figure>\n<h2 id=\"Managing-Links-Many-Meta-Relationship\"><a href=\"#Managing-Links-Many-Meta-Relationship\" class=\"headerlink\" title=\"Managing Links (Many Meta Relationship)\"></a>Managing Links (Many Meta Relationship)</h2><figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div></pre></td><td class=\"code\"><pre><div class=\"line\">link.add(relatedId, {<span class=\"attr\">someConditions</span>: <span class=\"literal\">true</span>}); <span class=\"comment\">// it also works with [relatedId1, relatedId2, relatedObj1, relatedObj2]</span></div><div class=\"line\">link.metadata(relatedId) <span class=\"comment\">// {_id: relatedId, someConditions: true}</span></div><div class=\"line\">link.metadata() <span class=\"comment\">// [{_id: relatedId, someConditions: true}, {_id: relatedI2, someThingElse: false}, ...]</span></div><div class=\"line\">link.metadata(relatedId, {<span class=\"attr\">otherStuff</span>: <span class=\"literal\">true</span>}); <span class=\"comment\">// will update the metadata</span></div><div class=\"line\">link.metadata(relatedId) <span class=\"comment\">// {_id: relatedId, someConditions: true, otherStuff: true}</span></div><div class=\"line\">link.remove(relatedId); <span class=\"comment\">// will remove the link with the relatedId along with the metadata</span></div></pre></td></tr></table></figure>\n<h2 id=\"Managing-Links-Inversed\"><a href=\"#Managing-Links-Inversed\" class=\"headerlink\" title=\"Managing Links - Inversed\"></a>Managing Links - Inversed</h2><p>This is an inversed link because the storage is stored in <em>Comments</em> collection.</p>\n<blockquote class=\"pullquote warning\"><p>When managing links from inversed side you are allowed to use set(), unset(), add(), remove(), \nto be able to use it in a natural language. postCommentsLink.set(commentId) wouldn’t make much sense in this case.</p>\n</blockquote>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div></pre></td><td class=\"code\"><pre><div class=\"line\">postCommentsLink = Posts.getLink(postId, <span class=\"string\">'comments'</span>);</div><div class=\"line\"></div><div class=\"line\">postCommentsLink.add(commentWithoutId) <span class=\"comment\">// will create a comment object in database and link it to post</span></div><div class=\"line\">postCommentsLink.add(arrayOfCommentsWithorWithoutIds) <span class=\"comment\">// for those without id it will create them and link them, for the others it will just link them</span></div><div class=\"line\"></div><div class=\"line\">postCommentsLink.remove(commentWithId) <span class=\"comment\">// it will remove the links</span></div><div class=\"line\">postCommentsLink.remove(_id) <span class=\"comment\">// it will remove the links</span></div></pre></td></tr></table></figure>"},{"title":"Query","description":"Reference API for Grapher Query","_content":"\n## Collection.createQuery()\n\n\nAvailable $filters: http://docs.meteor.com/api/collections.html#selectors\n\nAvailable $options: *sort*, *skip* and *limit* \n\n```js\nconst query = Posts.createQuery({\n $filters: {\n isPublished: true\n },\n $options: {},\n $filter({filters, options, params}) {\n // modify filters and options don't override\n }\n title: 1,\n nestedField: { // {} can be used for nested fields\n nestedFieldItem: 1\n }\n comments: {\n $filters: {\n isApproved: true // only retrieves the comments linekd to the post, that have isApproved: true\n }, // will only be applied to linked elements\n $options: {}, // will only be applied to linked elements\n $filter({filters, options, params}) {\n // params is global at query level, so params here are the same as params from the parent\n }\n linkField: 1\n }\n}, params)\n```\n\n## createQuery()\n\n```js\nimport { createQuery } from 'meteor/cultofcoders:grapher';\n\nconst query = createQuery({\n posts: {\n $filters: {},\n $options: {},\n $filter({filters, options, params}) {\n // modify filters and options don't override\n }\n title: 1,\n nestedField: { // {} can be used for nested fields\n nestedFieldItem: 1\n },\n comments: {\n $filters: {}, // will only be applied to linked elements\n $options: {}, // will only be applied to linked elements\n $filter({filters, options, params}) {\n // params is global at query level, so params here are the same as params from the parent\n },\n linkField: 1\n }\n }\n}, params)\n```\n\n## Query.fetch()\n```js\n// server-side\nquery.fetch() \n\n// impersonate user to work with exposure\nquery.fetch({userId: someUserId})\n```\n\n```js\n// client-side\nquery.fetch((err, data) => {\n // do something with data\n})\n```\n\n## Query.fetchOne()\n\nSame as fetch() but it always returns one result. Works very well when you want to retrieve a single item.\n\n## Query.fetchSync()\n\nYou can get the data directly via promises:\n```js\nasync function () {\n const result = await query.fetchSync()\n}\n```\n\n## Query.fetchOneSync()\n\n```js\nasync function () {\n const result = await query.fetchOneSync()\n}\n```\n\n## Query.setParams()\n\n```js\nquery.setParams(params).fetch()\n```\n\n## Query.subscribe()\n\nThis will subscribe to the current query configuration. If you want to change parameters. You will call *setParams()*, then subscribe again. \n\n```js\n// client-side\nquery.subscribe();\nquery.fetch(); // no callback needed, it will fetch from client-side collections\n```\n\n## Query.unsubscribe()\n\n```js\n// client-side\nquery.unsubscribe();\nquery.fetch(callback); // this time it needs callback because the query is now unsubscribed\n```\n\n## Query.clone()\n\nWhen you import your query, any changes you do to the parameters will stick. This is why it is recommended to clone it where you use it,\nso it becomes isolated.\n\n```js\nconst usableQuery = query.clone(newParameters);\n```\n\nAnother approach would be to export a factory function of createQuery like\n\n```js\nexport default () => {\n return createQuery(body);\n})\n```","source":"api/query.md","raw":"---\ntitle: Query\ndescription: Reference API for Grapher Query\n---\n\n## Collection.createQuery()\n\n\nAvailable $filters: http://docs.meteor.com/api/collections.html#selectors\n\nAvailable $options: *sort*, *skip* and *limit* \n\n```js\nconst query = Posts.createQuery({\n $filters: {\n isPublished: true\n },\n $options: {},\n $filter({filters, options, params}) {\n // modify filters and options don't override\n }\n title: 1,\n nestedField: { // {} can be used for nested fields\n nestedFieldItem: 1\n }\n comments: {\n $filters: {\n isApproved: true // only retrieves the comments linekd to the post, that have isApproved: true\n }, // will only be applied to linked elements\n $options: {}, // will only be applied to linked elements\n $filter({filters, options, params}) {\n // params is global at query level, so params here are the same as params from the parent\n }\n linkField: 1\n }\n}, params)\n```\n\n## createQuery()\n\n```js\nimport { createQuery } from 'meteor/cultofcoders:grapher';\n\nconst query = createQuery({\n posts: {\n $filters: {},\n $options: {},\n $filter({filters, options, params}) {\n // modify filters and options don't override\n }\n title: 1,\n nestedField: { // {} can be used for nested fields\n nestedFieldItem: 1\n },\n comments: {\n $filters: {}, // will only be applied to linked elements\n $options: {}, // will only be applied to linked elements\n $filter({filters, options, params}) {\n // params is global at query level, so params here are the same as params from the parent\n },\n linkField: 1\n }\n }\n}, params)\n```\n\n## Query.fetch()\n```js\n// server-side\nquery.fetch() \n\n// impersonate user to work with exposure\nquery.fetch({userId: someUserId})\n```\n\n```js\n// client-side\nquery.fetch((err, data) => {\n // do something with data\n})\n```\n\n## Query.fetchOne()\n\nSame as fetch() but it always returns one result. Works very well when you want to retrieve a single item.\n\n## Query.fetchSync()\n\nYou can get the data directly via promises:\n```js\nasync function () {\n const result = await query.fetchSync()\n}\n```\n\n## Query.fetchOneSync()\n\n```js\nasync function () {\n const result = await query.fetchOneSync()\n}\n```\n\n## Query.setParams()\n\n```js\nquery.setParams(params).fetch()\n```\n\n## Query.subscribe()\n\nThis will subscribe to the current query configuration. If you want to change parameters. You will call *setParams()*, then subscribe again. \n\n```js\n// client-side\nquery.subscribe();\nquery.fetch(); // no callback needed, it will fetch from client-side collections\n```\n\n## Query.unsubscribe()\n\n```js\n// client-side\nquery.unsubscribe();\nquery.fetch(callback); // this time it needs callback because the query is now unsubscribed\n```\n\n## Query.clone()\n\nWhen you import your query, any changes you do to the parameters will stick. This is why it is recommended to clone it where you use it,\nso it becomes isolated.\n\n```js\nconst usableQuery = query.clone(newParameters);\n```\n\nAnother approach would be to export a factory function of createQuery like\n\n```js\nexport default () => {\n return createQuery(body);\n})\n```","date":"2016-11-29T09:19:02.964Z","updated":"2016-11-29T09:19:02.964Z","path":"api/query.html","_id":"ciu5gd5tb00038sjxggjbbewj","comments":1,"layout":"page","content":"<h2 id=\"Collection-createQuery\"><a href=\"#Collection-createQuery\" class=\"headerlink\" title=\"Collection.createQuery()\"></a>Collection.createQuery()</h2><p>Available $filters: <a href=\"http://docs.meteor.com/api/collections.html#selectors\" target=\"_blank\" rel=\"external\">http://docs.meteor.com/api/collections.html#selectors</a></p>\n<p>Available $options: <em>sort</em>, <em>skip</em> and <em>limit</em> </p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div><div class=\"line\">20</div><div class=\"line\">21</div><div class=\"line\">22</div><div class=\"line\">23</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">const</span> query = Posts.createQuery({</div><div class=\"line\"> <span class=\"attr\">$filters</span>: {</div><div class=\"line\"> <span class=\"attr\">isPublished</span>: <span class=\"literal\">true</span></div><div class=\"line\"> },</div><div class=\"line\"> <span class=\"attr\">$options</span>: {},</div><div class=\"line\"> $filter({filters, options, params}) {</div><div class=\"line\"> <span class=\"comment\">// modify filters and options don't override</span></div><div class=\"line\"> }</div><div class=\"line\"> title: <span class=\"number\">1</span>,</div><div class=\"line\"> <span class=\"attr\">nestedField</span>: { <span class=\"comment\">// {} can be used for nested fields</span></div><div class=\"line\"> nestedFieldItem: <span class=\"number\">1</span></div><div class=\"line\"> }</div><div class=\"line\"> comments: {</div><div class=\"line\"> <span class=\"attr\">$filters</span>: {</div><div class=\"line\"> <span class=\"attr\">isApproved</span>: <span class=\"literal\">true</span> <span class=\"comment\">// only retrieves the comments linekd to the post, that have isApproved: true</span></div><div class=\"line\"> }, <span class=\"comment\">// will only be applied to linked elements</span></div><div class=\"line\"> $options: {}, <span class=\"comment\">// will only be applied to linked elements</span></div><div class=\"line\"> $filter({filters, options, params}) {</div><div class=\"line\"> <span class=\"comment\">// params is global at query level, so params here are the same as params from the parent</span></div><div class=\"line\"> }</div><div class=\"line\"> linkField: <span class=\"number\">1</span></div><div class=\"line\"> }</div><div class=\"line\">}, params)</div></pre></td></tr></table></figure>\n<h2 id=\"createQuery\"><a href=\"#createQuery\" class=\"headerlink\" title=\"createQuery()\"></a>createQuery()</h2><figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div><div class=\"line\">20</div><div class=\"line\">21</div><div class=\"line\">22</div><div class=\"line\">23</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">import</span> { createQuery } <span class=\"keyword\">from</span> <span class=\"string\">'meteor/cultofcoders:grapher'</span>;</div><div class=\"line\"></div><div class=\"line\"><span class=\"keyword\">const</span> query = createQuery({</div><div class=\"line\"> <span class=\"attr\">posts</span>: {</div><div class=\"line\"> <span class=\"attr\">$filters</span>: {},</div><div class=\"line\"> <span class=\"attr\">$options</span>: {},</div><div class=\"line\"> $filter({filters, options, params}) {</div><div class=\"line\"> <span class=\"comment\">// modify filters and options don't override</span></div><div class=\"line\"> }</div><div class=\"line\"> title: <span class=\"number\">1</span>,</div><div class=\"line\"> <span class=\"attr\">nestedField</span>: { <span class=\"comment\">// {} can be used for nested fields</span></div><div class=\"line\"> nestedFieldItem: <span class=\"number\">1</span></div><div class=\"line\"> },</div><div class=\"line\"> <span class=\"attr\">comments</span>: {</div><div class=\"line\"> <span class=\"attr\">$filters</span>: {}, <span class=\"comment\">// will only be applied to linked elements</span></div><div class=\"line\"> $options: {}, <span class=\"comment\">// will only be applied to linked elements</span></div><div class=\"line\"> $filter({filters, options, params}) {</div><div class=\"line\"> <span class=\"comment\">// params is global at query level, so params here are the same as params from the parent</span></div><div class=\"line\"> },</div><div class=\"line\"> <span class=\"attr\">linkField</span>: <span class=\"number\">1</span></div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\">}, params)</div></pre></td></tr></table></figure>\n<h2 id=\"Query-fetch\"><a href=\"#Query-fetch\" class=\"headerlink\" title=\"Query.fetch()\"></a>Query.fetch()</h2><figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">// server-side</span></div><div class=\"line\">query.fetch() </div><div class=\"line\"></div><div class=\"line\"><span class=\"comment\">// impersonate user to work with exposure</span></div><div class=\"line\">query.fetch({<span class=\"attr\">userId</span>: someUserId})</div></pre></td></tr></table></figure>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">// client-side</span></div><div class=\"line\">query.fetch(<span class=\"function\">(<span class=\"params\">err, data</span>) =></span> {</div><div class=\"line\"> <span class=\"comment\">// do something with data</span></div><div class=\"line\">})</div></pre></td></tr></table></figure>\n<h2 id=\"Query-fetchOne\"><a href=\"#Query-fetchOne\" class=\"headerlink\" title=\"Query.fetchOne()\"></a>Query.fetchOne()</h2><p>Same as fetch() but it always returns one result. Works very well when you want to retrieve a single item.</p>\n<h2 id=\"Query-fetchSync\"><a href=\"#Query-fetchSync\" class=\"headerlink\" title=\"Query.fetchSync()\"></a>Query.fetchSync()</h2><p>You can get the data directly via promises:\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">async</span> <span class=\"function\"><span class=\"keyword\">function</span> (<span class=\"params\"></span>) </span>{</div><div class=\"line\"> <span class=\"keyword\">const</span> result = <span class=\"keyword\">await</span> query.fetchSync()</div><div class=\"line\">}</div></pre></td></tr></table></figure></p>\n<h2 id=\"Query-fetchOneSync\"><a href=\"#Query-fetchOneSync\" class=\"headerlink\" title=\"Query.fetchOneSync()\"></a>Query.fetchOneSync()</h2><figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">async</span> <span class=\"function\"><span class=\"keyword\">function</span> (<span class=\"params\"></span>) </span>{</div><div class=\"line\"> <span class=\"keyword\">const</span> result = <span class=\"keyword\">await</span> query.fetchOneSync()</div><div class=\"line\">}</div></pre></td></tr></table></figure>\n<h2 id=\"Query-setParams\"><a href=\"#Query-setParams\" class=\"headerlink\" title=\"Query.setParams()\"></a>Query.setParams()</h2><figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\">query.setParams(params).fetch()</div></pre></td></tr></table></figure>\n<h2 id=\"Query-subscribe\"><a href=\"#Query-subscribe\" class=\"headerlink\" title=\"Query.subscribe()\"></a>Query.subscribe()</h2><p>This will subscribe to the current query configuration. If you want to change parameters. You will call <em>setParams()</em>, then subscribe again. </p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">// client-side</span></div><div class=\"line\">query.subscribe();</div><div class=\"line\">query.fetch(); <span class=\"comment\">// no callback needed, it will fetch from client-side collections</span></div></pre></td></tr></table></figure>\n<h2 id=\"Query-unsubscribe\"><a href=\"#Query-unsubscribe\" class=\"headerlink\" title=\"Query.unsubscribe()\"></a>Query.unsubscribe()</h2><figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">// client-side</span></div><div class=\"line\">query.unsubscribe();</div><div class=\"line\">query.fetch(callback); <span class=\"comment\">// this time it needs callback because the query is now unsubscribed</span></div></pre></td></tr></table></figure>\n<h2 id=\"Query-clone\"><a href=\"#Query-clone\" class=\"headerlink\" title=\"Query.clone()\"></a>Query.clone()</h2><p>When you import your query, any changes you do to the parameters will stick. This is why it is recommended to clone it where you use it,\nso it becomes isolated.</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">const</span> usableQuery = query.clone(newParameters);</div></pre></td></tr></table></figure>\n<p>Another approach would be to export a factory function of createQuery like</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">export</span> <span class=\"keyword\">default</span> () => {</div><div class=\"line\"> <span class=\"keyword\">return</span> createQuery(body);</div><div class=\"line\">})</div></pre></td></tr></table></figure>","excerpt":"","more":"<h2 id=\"Collection-createQuery\"><a href=\"#Collection-createQuery\" class=\"headerlink\" title=\"Collection.createQuery()\"></a>Collection.createQuery()</h2><p>Available $filters: <a href=\"http://docs.meteor.com/api/collections.html#selectors\">http://docs.meteor.com/api/collections.html#selectors</a></p>\n<p>Available $options: <em>sort</em>, <em>skip</em> and <em>limit</em> </p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div><div class=\"line\">20</div><div class=\"line\">21</div><div class=\"line\">22</div><div class=\"line\">23</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">const</span> query = Posts.createQuery({</div><div class=\"line\"> <span class=\"attr\">$filters</span>: {</div><div class=\"line\"> <span class=\"attr\">isPublished</span>: <span class=\"literal\">true</span></div><div class=\"line\"> },</div><div class=\"line\"> <span class=\"attr\">$options</span>: {},</div><div class=\"line\"> $filter({filters, options, params}) {</div><div class=\"line\"> <span class=\"comment\">// modify filters and options don't override</span></div><div class=\"line\"> }</div><div class=\"line\"> title: <span class=\"number\">1</span>,</div><div class=\"line\"> <span class=\"attr\">nestedField</span>: { <span class=\"comment\">// {} can be used for nested fields</span></div><div class=\"line\"> nestedFieldItem: <span class=\"number\">1</span></div><div class=\"line\"> }</div><div class=\"line\"> comments: {</div><div class=\"line\"> <span class=\"attr\">$filters</span>: {</div><div class=\"line\"> <span class=\"attr\">isApproved</span>: <span class=\"literal\">true</span> <span class=\"comment\">// only retrieves the comments linekd to the post, that have isApproved: true</span></div><div class=\"line\"> }, <span class=\"comment\">// will only be applied to linked elements</span></div><div class=\"line\"> $options: {}, <span class=\"comment\">// will only be applied to linked elements</span></div><div class=\"line\"> $filter({filters, options, params}) {</div><div class=\"line\"> <span class=\"comment\">// params is global at query level, so params here are the same as params from the parent</span></div><div class=\"line\"> }</div><div class=\"line\"> linkField: <span class=\"number\">1</span></div><div class=\"line\"> }</div><div class=\"line\">}, params)</div></pre></td></tr></table></figure>\n<h2 id=\"createQuery\"><a href=\"#createQuery\" class=\"headerlink\" title=\"createQuery()\"></a>createQuery()</h2><figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div><div class=\"line\">20</div><div class=\"line\">21</div><div class=\"line\">22</div><div class=\"line\">23</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">import</span> { createQuery } <span class=\"keyword\">from</span> <span class=\"string\">'meteor/cultofcoders:grapher'</span>;</div><div class=\"line\"></div><div class=\"line\"><span class=\"keyword\">const</span> query = createQuery({</div><div class=\"line\"> <span class=\"attr\">posts</span>: {</div><div class=\"line\"> <span class=\"attr\">$filters</span>: {},</div><div class=\"line\"> <span class=\"attr\">$options</span>: {},</div><div class=\"line\"> $filter({filters, options, params}) {</div><div class=\"line\"> <span class=\"comment\">// modify filters and options don't override</span></div><div class=\"line\"> }</div><div class=\"line\"> title: <span class=\"number\">1</span>,</div><div class=\"line\"> <span class=\"attr\">nestedField</span>: { <span class=\"comment\">// {} can be used for nested fields</span></div><div class=\"line\"> nestedFieldItem: <span class=\"number\">1</span></div><div class=\"line\"> },</div><div class=\"line\"> <span class=\"attr\">comments</span>: {</div><div class=\"line\"> <span class=\"attr\">$filters</span>: {}, <span class=\"comment\">// will only be applied to linked elements</span></div><div class=\"line\"> $options: {}, <span class=\"comment\">// will only be applied to linked elements</span></div><div class=\"line\"> $filter({filters, options, params}) {</div><div class=\"line\"> <span class=\"comment\">// params is global at query level, so params here are the same as params from the parent</span></div><div class=\"line\"> },</div><div class=\"line\"> <span class=\"attr\">linkField</span>: <span class=\"number\">1</span></div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\">}, params)</div></pre></td></tr></table></figure>\n<h2 id=\"Query-fetch\"><a href=\"#Query-fetch\" class=\"headerlink\" title=\"Query.fetch()\"></a>Query.fetch()</h2><figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">// server-side</span></div><div class=\"line\">query.fetch() </div><div class=\"line\"></div><div class=\"line\"><span class=\"comment\">// impersonate user to work with exposure</span></div><div class=\"line\">query.fetch({<span class=\"attr\">userId</span>: someUserId})</div></pre></td></tr></table></figure>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">// client-side</span></div><div class=\"line\">query.fetch(<span class=\"function\">(<span class=\"params\">err, data</span>) =></span> {</div><div class=\"line\"> <span class=\"comment\">// do something with data</span></div><div class=\"line\">})</div></pre></td></tr></table></figure>\n<h2 id=\"Query-fetchOne\"><a href=\"#Query-fetchOne\" class=\"headerlink\" title=\"Query.fetchOne()\"></a>Query.fetchOne()</h2><p>Same as fetch() but it always returns one result. Works very well when you want to retrieve a single item.</p>\n<h2 id=\"Query-fetchSync\"><a href=\"#Query-fetchSync\" class=\"headerlink\" title=\"Query.fetchSync()\"></a>Query.fetchSync()</h2><p>You can get the data directly via promises:\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">async</span> <span class=\"function\"><span class=\"keyword\">function</span> (<span class=\"params\"></span>) </span>{</div><div class=\"line\"> <span class=\"keyword\">const</span> result = <span class=\"keyword\">await</span> query.fetchSync()</div><div class=\"line\">}</div></pre></td></tr></table></figure></p>\n<h2 id=\"Query-fetchOneSync\"><a href=\"#Query-fetchOneSync\" class=\"headerlink\" title=\"Query.fetchOneSync()\"></a>Query.fetchOneSync()</h2><figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">async</span> <span class=\"function\"><span class=\"keyword\">function</span> (<span class=\"params\"></span>) </span>{</div><div class=\"line\"> <span class=\"keyword\">const</span> result = <span class=\"keyword\">await</span> query.fetchOneSync()</div><div class=\"line\">}</div></pre></td></tr></table></figure>\n<h2 id=\"Query-setParams\"><a href=\"#Query-setParams\" class=\"headerlink\" title=\"Query.setParams()\"></a>Query.setParams()</h2><figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\">query.setParams(params).fetch()</div></pre></td></tr></table></figure>\n<h2 id=\"Query-subscribe\"><a href=\"#Query-subscribe\" class=\"headerlink\" title=\"Query.subscribe()\"></a>Query.subscribe()</h2><p>This will subscribe to the current query configuration. If you want to change parameters. You will call <em>setParams()</em>, then subscribe again. </p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">// client-side</span></div><div class=\"line\">query.subscribe();</div><div class=\"line\">query.fetch(); <span class=\"comment\">// no callback needed, it will fetch from client-side collections</span></div></pre></td></tr></table></figure>\n<h2 id=\"Query-unsubscribe\"><a href=\"#Query-unsubscribe\" class=\"headerlink\" title=\"Query.unsubscribe()\"></a>Query.unsubscribe()</h2><figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">// client-side</span></div><div class=\"line\">query.unsubscribe();</div><div class=\"line\">query.fetch(callback); <span class=\"comment\">// this time it needs callback because the query is now unsubscribed</span></div></pre></td></tr></table></figure>\n<h2 id=\"Query-clone\"><a href=\"#Query-clone\" class=\"headerlink\" title=\"Query.clone()\"></a>Query.clone()</h2><p>When you import your query, any changes you do to the parameters will stick. This is why it is recommended to clone it where you use it,\nso it becomes isolated.</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">const</span> usableQuery = query.clone(newParameters);</div></pre></td></tr></table></figure>\n<p>Another approach would be to export a factory function of createQuery like</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">export</span> <span class=\"keyword\">default</span> () => {</div><div class=\"line\"> <span class=\"keyword\">return</span> createQuery(body);</div><div class=\"line\">})</div></pre></td></tr></table></figure>"},{"title":"Managing Links","description":"Managing Links (Relationships) between Mongo Collections easily","_content":"\n## Introduction\n\nThis module is a collection relationship manager, lets you specify linking information between collections, \ngives you ability to easily manipulate these links (like add, remove), and provides an easy way to fetch them.\n\nIn addition to that, you also have the ability create *resolver* links that can make REST-API calls or link with any type of database.\n\nWhen linking MongoDB collections, we support 4 different ways:\n\n#### One\n\nWe use this when we want to reference a single Document. For example, a comment has one author. Or a post has one author.\n\n```js\n// Comment Document\n{\n ...\n userId: 'XXX'\n}\n```\n\n#### Many\n\nWe use this when we want to store multiple references to a collection. This can be viewed as a *Many-To-Many* SQL relationship, but not necessarily.\nFor example, a user may belong in multiple groups:\n\n```js\n// User Document\n{\n ...\n groupIds: ['XXX', 'YYY']\n}\n```\n\n#### One Meta\nMeta comes from *metadata*. This is used when we want to store additional information about the link. \nFor example, if a user belongs to a single group, we want to store the fact that he is an Admin or not.\n\nThis relationship can be emulated in different ways. We could also store via a *Many* relationship \"adminIds\" at Group Level.\nThere is no right or wrong. Just choose what's best fit.\n\n```js\n// User Document\n{\n ...\n groupId: {\n _id: 'XXX', isAdmin: true\n }\n}\n```\n\n#### Many Meta\nSame as the scenario in One Meta, but in this case, a user can belong to multiple groups and he can be admin only to some.\n\n```js\n// User Document\n{\n ...\n groupIds: [\n {_id: 'XXX', isAdmin: true},\n {_id: 'YYY', isAdmin: false}\n ]\n}\n```\n\nTo emulate that you can also have done it in Group Document:\n\n```js\n// Group Document\n{\n ...\n userIds: [\n {_id: 'XXX', isAdmin: true},\n {_id: 'YYY', isAdmin: false},\n ]\n}\n```\n\nOur First Link\n--------------\n\nYou have a Comment that is posted by an User. \nWe either store userId at Comment level, or store commentIds at User level.\nThe second one doesn't make much sense, so we'll explore the first one.\n\nIf we store \"userId\" in Comment document. We have a \"One\" relationship.\n\n```js\n// comment document would look like:\n{\n _id: 'XXXXXXXXXXXXXXX',\n text: 'Hello Grapher!',\n userId: 'XXXXXXXXXXXXXXX'\n}\n```\n\nTo create this kind of link we would do:\n```js\nconst Users = Meteor.users;\nconst Comments = new Mongo.Collection('comments');\n\nComments.addLinks({\n user: { // user represents the link name, can be any name you wish\n type: 'one', // we would have used 'many' if we wanted to store multiple user ids\n collection: Users,\n field: 'userId' // optional, if not specified it will generate a specific field.\n }\n});\n```\n\nWe will use the *getLink* method, which is an object that allows us to fetch, and modify the linked elements.\n\n```js\nconst commentId = Comments.insert({text: 'Our first linked comment.'});\nconst userLink = Comments.getLink(commentId, 'user'); // we retrieve the link object for commentId and 'user'\n\n// if you have the comment object with an _id, you can also do Comments.getLink(comment, 'user')\nuserLink.set(this.userId); // will update userId\nuserLink.unset(); // will make userId null\n\nuserLink.fetch(); // returns the user object, if it was a multi relationship it would have returned an array\nuserLink.find(); // returns a Mongo.Cursor, but if you run .fetch() on it will return an array regardless of the relationship type.\n\n// set/unset makes an update immediately into the database, should be run server side.\n```\n\n{% pullquote 'warning' %}\nRemoving/unsetting the link, will not affect the related document. If you want to remove it from the database, you will have to do it manually.\n{% endpullquote %}\n\nInversed Links\n--------------\n\nAll good but I may want at the user level to fetch all my comments I posted. This is where we introduce the concept of *inversed links*.\nAn *inversed link* basically means that the information about the link is stored on the other side. In our case, in the Comment document.\n\n```js\nUsers.addLinks({\n 'comments': {\n collection: Comments,\n inversedBy: 'user'\n }\n});\n\nlet comments = [];\nconst commentsLink = Users.getLink(this.userId, 'comments');\ncomments = commentsLink.find().fetch()\n// or\ncomments = commentsLink.fetch()\n// or filter your query even more using find(filters, options)\ncomments = commentsLink.find({text: 'Our first linked comment.'}, {limit: 10}).fetch()\n// or\ncomments = commentsLink.fetch({text: 'Our first linked comment.'}, {limit: 10})\n```\n\n{% pullquote 'warning' %}\nIf you use filters when fetching from a link, the filters will be applied only for the linked documents.\n{% endpullquote %}\n\nNow, let's continue our journey and assume the comment might have different tags. \nSo let's use a *Many* relationship:\n\n```js\nComments.addLinks({\n tags: {\n collection: Tags,\n type: 'many'\n }\n})\n\nconst tagLink = Comments.getLink(commentId, 'tags');\ntagLink.add(tagId);\ntagLink.add(tagObject); // object must contain _id to be able to identify it, \n\n// IMPORTANT: if the object does not contain _id, the object will be created in the database for you automatically\ntagLink.add({name: 'New Tag'}) // will create a tag document in Tags collection\n\n// Also supports:\ntagLink.add([tagId1, tagId2]);\ntagLink.add([tagObject1, tagObject2]);\n\n// Same arguments are supported by tagLink.remove(...)\n```\n\nKeep in mind:\nFor single relationships *One* and *One Meta* we use set() and unset().\nFor many relationships *Many* and *Many Meta* we use add() and remove().\n\n#### Chain commands that run updates easily:\n\n```js\ntagLink.remove(oldTagId).add(newTagId);\nexampleLink.set('XXX').unset();\n```\n\nMeta Links\n----------\n\nA meta relationship is very useful because you may need to store information *about the relationship*. \nSuch as an user can belong to certain groups, but he is an admin only to some group\n \nSo instead of creating a separate collection for this, or poluting the groups document, we could use meta relationships.\n\n```js\nUsers.addLinks({\n groups: {\n type: 'many'\n metadata: {} // it is enough to specify metadata as an empty object to make it clear we are dealing with a meta relation\n }\n});\n\nconst groupsLink = Users.getLink(userId, 'groups');\ngroupsLink.add(groupId, {isAdmin: true});\n\n// metadata getter\ngroupsLink.metadata(groupId) // returns {isAdmin: true, _id: groupId}}\n// metadata setter\ngroupsLink.metadata(groupId, {isAdmin: false}) // runs the update for you automatically\n```\n\nThe same principles apply to *One Meta* relationships, but you don't need to specify the _id:\n\n```js\nUsers.addLinks({\n group: {type: 'one', metadata: {}}\n})\n\nconst groupLink = Users.getLink(userId, 'group');\ngroupLink.set(groupId, {isAdmin: true});\ngroupLink.metadata() // returns {isAdmin: true, _id: groupId}}\ngroupLink.metadata({isAdmin: false}) // runs the update in the database.\n```\n\nMeta filters\n------------\n\nGiven a relationship between 2 entities: Users and Groups\n```js\nUsers.addLinks({\n groups: {\n collection: Groups,\n type: 'many',\n metadata: {\n isAdmin: { type: Boolean }\n }\n }\n})\n```\n\nYou can now fetch only the groups you are admin to like this:\n\n```js\nconst groupsLink = Users.getLink(userId, 'groups');\ngroupsLink.fetch({$meta: {isAdmin: true}});\n```\n\nIt also works from the inversed side as well:\n```js\nGroups.addLinks({\n users: {\n collection: Users,\n inversedBy: 'groups'\n }\n})\n\n\nconst usersLink = Groups.getLink(groupId, 'users');\nusersLink.fetch({$meta: {isAdmin: true}});\n```\n\n{% pullquote 'warning' %}\nMeta filters also works with Query\n{% endpullquote %}\n\nLink Loopback\n-------------\n\nReference the same collection in the link. For tree-like database structures this is great.\n\n```js\nUsers.addLinks({\n children: {\n collection: Users,\n type: 'many'\n }\n parent: {\n collection: Users,\n inversedBy: 'children'\n }\n})\n```\n\n```js\nconst childrenLink = Users.getLink(this.userId, 'children');\nchildrenLink.fetch() // array of ob\nconst parentLink = Users.getLink(this.userId, 'children');\nparentLink.fetch() // single object\n```\n\nResolver Links\n--------------\n```js\nUsers.addLinks({\n tickets: {\n resolver(user, arg1, arg2) { // first argument will be the parent, next arguments are what is passed in fetch() or find()\n const runner = Meteor.wrapAsync(HTTP.call);\n return runner(\"GET\", \"https://api.example.com/tickets\", {id: user.exampleApiId});\n }\n }\n});\n\nconst ticketLink = Users.getLink(this.userId, 'tickets');\nticketsLink.fetch(arg1, arg2);\nticketsLink.find(arg1, arg2); // fetch() and find() they are equivalent for Resolver Links \n```\n\n{% pullquote 'warning' %}\nYou must use a sync function for this to work. Read more about [Meteor.wrapAsync](https://docs.meteor.com/api/core.html#Meteor-wrapAsync).\n{% endpullquote %}\n\n{% pullquote 'info' %}\nYou can also use resolver for special database queries for example, you may need to get only the messages that he has not seen yet.\n{% endpullquote %}\n\n\n```js\nUsers.addLinks({\n unreadMessages: {\n resolve(user) {\n return Messages.find({receiverId: user._id, isRead: false}).fetch();\n }\n }\n});\n```\n\n\nSimpleSchema\n-----------------------------\n\nIt is very likely that you would use SimpleSchema to ensure a data-structure for your documents, and prevent bad data to be inserted.\nThis library automatically detects whether you have a schema attached to your collection or not, and will add fields with proper schema definitions.\n\nIMPORTANT! In order for this to work without problems, make sure your schema is attached before defining links. These are the appended schemas by link type.\n\n#### One Relationships\n\n```js\nfieldName: {\n type: String,\n optional: true\n}\n```\n\n#### Many Relationships\n\n```js\nfieldName: {\n type: [String], \n optional: true\n}\n```\n\n#### Meta Relationships\n\nFor meta relationships, it creates a blackbox schema if the metadata option contains no keys\n\nExample:\n```js\nUsers.addLinks({\n group: {\n type: 'one', \n field: 'groupId',\n metadata: {}\n }\n});\n```\n\nThis will append to your schema:\n```js\ngroupId: {\n type: Object,\n blackbox: true, \n optional: true\n}\n```\n\nExample:\n```js\nUsers.addLinks({\n group: {\n type: 'one', \n field: 'groupId',\n metadata: {\n isAdmin: {type: Boolean, optional: true}\n }\n }\n});\n```\n\nThis will append to your schema:\n```js\ngroupId: {\n type: Object,\n blackbox: true, \n optional: true\n}\ngroupId.$._id: {type: String}\ngroupId.$.isAdmin: {type: Boolean, optional: true}\n```\n\n{% pullquote 'warning' %}\n_id field is put by default.\n{% endpullquote %}\n\nIf you have a many meta relationship:\n```js\nconst metadataSchema = {\n _id: {type: String},\n isAdmin: {type: Boolean, optional: true}\n}\n```\n\nAppended schema will look like:\n```js\ngroupIds: {\n type: [metadataSchema],\n optional: true\n}\n```\n\n\nData Consistency\n----------------\n\nLet's say I have a \"Thread\" with multiple \"Members\". If a \"Member\" is deleted from the database, we don't want to keep unexisting references.\nThis is why if we delete a member, thread document should be cleaned.\n\n{% pullquote 'warning' %}\nThis works for any kind of relationship.\n{% endpullquote %}\n\nThis is achieved by using [https://atmospherejs.com/matb33/collection-hooks](https://atmospherejs.com/matb33/collection-hooks) package.\nAnd it only works if Member contains the inversed link to Thread.\n\nLet's see how that works'\n\n```js\nThreads.addLinks({\n 'members': {\n collection: Members,\n type: 'many'\n }\n});\n\nMembers.addLinks({\n 'threads': {\n collection: Threads,\n inversedBy: 'members'\n }\n});\n```\n\nWhen *Member* is removed from the database, it will look for all the threads of that member.\nAnd it will remove it from the fieldStorage. This way your data will be *consistent* without having to deal with it.\n\nAutoremoval\n-----------\n```js\nMembers.addLinks({\n 'posts': {\n collection: Posts,\n type: 'many',\n autoremove: true\n }\n});\n```\n\nBe careful with this one! \nWhen Member document is deleted, all posts will be deleted.\n\nThis works from direct and inversed side as well. Use with caution.\n\nIndexing\n--------\n\n```js\nMembers.addLinks({\n 'posts': {\n collection: Posts,\n type: 'many',\n index: true\n }\n});\n```\n\n\n{% pullquote 'warning' %}\nBy using *index: true* option, it will call _ensureIndex automatically on your collection.\nThis will give you a performance boost when you are searching from the \"related\" link, in our case, from \"Posts\".\n{% endpullquote %}\n\n\n","source":"guide/links.md","raw":"---\ntitle: Managing Links\ndescription: Managing Links (Relationships) between Mongo Collections easily\n---\n\n## Introduction\n\nThis module is a collection relationship manager, lets you specify linking information between collections, \ngives you ability to easily manipulate these links (like add, remove), and provides an easy way to fetch them.\n\nIn addition to that, you also have the ability create *resolver* links that can make REST-API calls or link with any type of database.\n\nWhen linking MongoDB collections, we support 4 different ways:\n\n#### One\n\nWe use this when we want to reference a single Document. For example, a comment has one author. Or a post has one author.\n\n```js\n// Comment Document\n{\n ...\n userId: 'XXX'\n}\n```\n\n#### Many\n\nWe use this when we want to store multiple references to a collection. This can be viewed as a *Many-To-Many* SQL relationship, but not necessarily.\nFor example, a user may belong in multiple groups:\n\n```js\n// User Document\n{\n ...\n groupIds: ['XXX', 'YYY']\n}\n```\n\n#### One Meta\nMeta comes from *metadata*. This is used when we want to store additional information about the link. \nFor example, if a user belongs to a single group, we want to store the fact that he is an Admin or not.\n\nThis relationship can be emulated in different ways. We could also store via a *Many* relationship \"adminIds\" at Group Level.\nThere is no right or wrong. Just choose what's best fit.\n\n```js\n// User Document\n{\n ...\n groupId: {\n _id: 'XXX', isAdmin: true\n }\n}\n```\n\n#### Many Meta\nSame as the scenario in One Meta, but in this case, a user can belong to multiple groups and he can be admin only to some.\n\n```js\n// User Document\n{\n ...\n groupIds: [\n {_id: 'XXX', isAdmin: true},\n {_id: 'YYY', isAdmin: false}\n ]\n}\n```\n\nTo emulate that you can also have done it in Group Document:\n\n```js\n// Group Document\n{\n ...\n userIds: [\n {_id: 'XXX', isAdmin: true},\n {_id: 'YYY', isAdmin: false},\n ]\n}\n```\n\nOur First Link\n--------------\n\nYou have a Comment that is posted by an User. \nWe either store userId at Comment level, or store commentIds at User level.\nThe second one doesn't make much sense, so we'll explore the first one.\n\nIf we store \"userId\" in Comment document. We have a \"One\" relationship.\n\n```js\n// comment document would look like:\n{\n _id: 'XXXXXXXXXXXXXXX',\n text: 'Hello Grapher!',\n userId: 'XXXXXXXXXXXXXXX'\n}\n```\n\nTo create this kind of link we would do:\n```js\nconst Users = Meteor.users;\nconst Comments = new Mongo.Collection('comments');\n\nComments.addLinks({\n user: { // user represents the link name, can be any name you wish\n type: 'one', // we would have used 'many' if we wanted to store multiple user ids\n collection: Users,\n field: 'userId' // optional, if not specified it will generate a specific field.\n }\n});\n```\n\nWe will use the *getLink* method, which is an object that allows us to fetch, and modify the linked elements.\n\n```js\nconst commentId = Comments.insert({text: 'Our first linked comment.'});\nconst userLink = Comments.getLink(commentId, 'user'); // we retrieve the link object for commentId and 'user'\n\n// if you have the comment object with an _id, you can also do Comments.getLink(comment, 'user')\nuserLink.set(this.userId); // will update userId\nuserLink.unset(); // will make userId null\n\nuserLink.fetch(); // returns the user object, if it was a multi relationship it would have returned an array\nuserLink.find(); // returns a Mongo.Cursor, but if you run .fetch() on it will return an array regardless of the relationship type.\n\n// set/unset makes an update immediately into the database, should be run server side.\n```\n\n{% pullquote 'warning' %}\nRemoving/unsetting the link, will not affect the related document. If you want to remove it from the database, you will have to do it manually.\n{% endpullquote %}\n\nInversed Links\n--------------\n\nAll good but I may want at the user level to fetch all my comments I posted. This is where we introduce the concept of *inversed links*.\nAn *inversed link* basically means that the information about the link is stored on the other side. In our case, in the Comment document.\n\n```js\nUsers.addLinks({\n 'comments': {\n collection: Comments,\n inversedBy: 'user'\n }\n});\n\nlet comments = [];\nconst commentsLink = Users.getLink(this.userId, 'comments');\ncomments = commentsLink.find().fetch()\n// or\ncomments = commentsLink.fetch()\n// or filter your query even more using find(filters, options)\ncomments = commentsLink.find({text: 'Our first linked comment.'}, {limit: 10}).fetch()\n// or\ncomments = commentsLink.fetch({text: 'Our first linked comment.'}, {limit: 10})\n```\n\n{% pullquote 'warning' %}\nIf you use filters when fetching from a link, the filters will be applied only for the linked documents.\n{% endpullquote %}\n\nNow, let's continue our journey and assume the comment might have different tags. \nSo let's use a *Many* relationship:\n\n```js\nComments.addLinks({\n tags: {\n collection: Tags,\n type: 'many'\n }\n})\n\nconst tagLink = Comments.getLink(commentId, 'tags');\ntagLink.add(tagId);\ntagLink.add(tagObject); // object must contain _id to be able to identify it, \n\n// IMPORTANT: if the object does not contain _id, the object will be created in the database for you automatically\ntagLink.add({name: 'New Tag'}) // will create a tag document in Tags collection\n\n// Also supports:\ntagLink.add([tagId1, tagId2]);\ntagLink.add([tagObject1, tagObject2]);\n\n// Same arguments are supported by tagLink.remove(...)\n```\n\nKeep in mind:\nFor single relationships *One* and *One Meta* we use set() and unset().\nFor many relationships *Many* and *Many Meta* we use add() and remove().\n\n#### Chain commands that run updates easily:\n\n```js\ntagLink.remove(oldTagId).add(newTagId);\nexampleLink.set('XXX').unset();\n```\n\nMeta Links\n----------\n\nA meta relationship is very useful because you may need to store information *about the relationship*. \nSuch as an user can belong to certain groups, but he is an admin only to some group\n \nSo instead of creating a separate collection for this, or poluting the groups document, we could use meta relationships.\n\n```js\nUsers.addLinks({\n groups: {\n type: 'many'\n metadata: {} // it is enough to specify metadata as an empty object to make it clear we are dealing with a meta relation\n }\n});\n\nconst groupsLink = Users.getLink(userId, 'groups');\ngroupsLink.add(groupId, {isAdmin: true});\n\n// metadata getter\ngroupsLink.metadata(groupId) // returns {isAdmin: true, _id: groupId}}\n// metadata setter\ngroupsLink.metadata(groupId, {isAdmin: false}) // runs the update for you automatically\n```\n\nThe same principles apply to *One Meta* relationships, but you don't need to specify the _id:\n\n```js\nUsers.addLinks({\n group: {type: 'one', metadata: {}}\n})\n\nconst groupLink = Users.getLink(userId, 'group');\ngroupLink.set(groupId, {isAdmin: true});\ngroupLink.metadata() // returns {isAdmin: true, _id: groupId}}\ngroupLink.metadata({isAdmin: false}) // runs the update in the database.\n```\n\nMeta filters\n------------\n\nGiven a relationship between 2 entities: Users and Groups\n```js\nUsers.addLinks({\n groups: {\n collection: Groups,\n type: 'many',\n metadata: {\n isAdmin: { type: Boolean }\n }\n }\n})\n```\n\nYou can now fetch only the groups you are admin to like this:\n\n```js\nconst groupsLink = Users.getLink(userId, 'groups');\ngroupsLink.fetch({$meta: {isAdmin: true}});\n```\n\nIt also works from the inversed side as well:\n```js\nGroups.addLinks({\n users: {\n collection: Users,\n inversedBy: 'groups'\n }\n})\n\n\nconst usersLink = Groups.getLink(groupId, 'users');\nusersLink.fetch({$meta: {isAdmin: true}});\n```\n\n{% pullquote 'warning' %}\nMeta filters also works with Query\n{% endpullquote %}\n\nLink Loopback\n-------------\n\nReference the same collection in the link. For tree-like database structures this is great.\n\n```js\nUsers.addLinks({\n children: {\n collection: Users,\n type: 'many'\n }\n parent: {\n collection: Users,\n inversedBy: 'children'\n }\n})\n```\n\n```js\nconst childrenLink = Users.getLink(this.userId, 'children');\nchildrenLink.fetch() // array of ob\nconst parentLink = Users.getLink(this.userId, 'children');\nparentLink.fetch() // single object\n```\n\nResolver Links\n--------------\n```js\nUsers.addLinks({\n tickets: {\n resolver(user, arg1, arg2) { // first argument will be the parent, next arguments are what is passed in fetch() or find()\n const runner = Meteor.wrapAsync(HTTP.call);\n return runner(\"GET\", \"https://api.example.com/tickets\", {id: user.exampleApiId});\n }\n }\n});\n\nconst ticketLink = Users.getLink(this.userId, 'tickets');\nticketsLink.fetch(arg1, arg2);\nticketsLink.find(arg1, arg2); // fetch() and find() they are equivalent for Resolver Links \n```\n\n{% pullquote 'warning' %}\nYou must use a sync function for this to work. Read more about [Meteor.wrapAsync](https://docs.meteor.com/api/core.html#Meteor-wrapAsync).\n{% endpullquote %}\n\n{% pullquote 'info' %}\nYou can also use resolver for special database queries for example, you may need to get only the messages that he has not seen yet.\n{% endpullquote %}\n\n\n```js\nUsers.addLinks({\n unreadMessages: {\n resolve(user) {\n return Messages.find({receiverId: user._id, isRead: false}).fetch();\n }\n }\n});\n```\n\n\nSimpleSchema\n-----------------------------\n\nIt is very likely that you would use SimpleSchema to ensure a data-structure for your documents, and prevent bad data to be inserted.\nThis library automatically detects whether you have a schema attached to your collection or not, and will add fields with proper schema definitions.\n\nIMPORTANT! In order for this to work without problems, make sure your schema is attached before defining links. These are the appended schemas by link type.\n\n#### One Relationships\n\n```js\nfieldName: {\n type: String,\n optional: true\n}\n```\n\n#### Many Relationships\n\n```js\nfieldName: {\n type: [String], \n optional: true\n}\n```\n\n#### Meta Relationships\n\nFor meta relationships, it creates a blackbox schema if the metadata option contains no keys\n\nExample:\n```js\nUsers.addLinks({\n group: {\n type: 'one', \n field: 'groupId',\n metadata: {}\n }\n});\n```\n\nThis will append to your schema:\n```js\ngroupId: {\n type: Object,\n blackbox: true, \n optional: true\n}\n```\n\nExample:\n```js\nUsers.addLinks({\n group: {\n type: 'one', \n field: 'groupId',\n metadata: {\n isAdmin: {type: Boolean, optional: true}\n }\n }\n});\n```\n\nThis will append to your schema:\n```js\ngroupId: {\n type: Object,\n blackbox: true, \n optional: true\n}\ngroupId.$._id: {type: String}\ngroupId.$.isAdmin: {type: Boolean, optional: true}\n```\n\n{% pullquote 'warning' %}\n_id field is put by default.\n{% endpullquote %}\n\nIf you have a many meta relationship:\n```js\nconst metadataSchema = {\n _id: {type: String},\n isAdmin: {type: Boolean, optional: true}\n}\n```\n\nAppended schema will look like:\n```js\ngroupIds: {\n type: [metadataSchema],\n optional: true\n}\n```\n\n\nData Consistency\n----------------\n\nLet's say I have a \"Thread\" with multiple \"Members\". If a \"Member\" is deleted from the database, we don't want to keep unexisting references.\nThis is why if we delete a member, thread document should be cleaned.\n\n{% pullquote 'warning' %}\nThis works for any kind of relationship.\n{% endpullquote %}\n\nThis is achieved by using [https://atmospherejs.com/matb33/collection-hooks](https://atmospherejs.com/matb33/collection-hooks) package.\nAnd it only works if Member contains the inversed link to Thread.\n\nLet's see how that works'\n\n```js\nThreads.addLinks({\n 'members': {\n collection: Members,\n type: 'many'\n }\n});\n\nMembers.addLinks({\n 'threads': {\n collection: Threads,\n inversedBy: 'members'\n }\n});\n```\n\nWhen *Member* is removed from the database, it will look for all the threads of that member.\nAnd it will remove it from the fieldStorage. This way your data will be *consistent* without having to deal with it.\n\nAutoremoval\n-----------\n```js\nMembers.addLinks({\n 'posts': {\n collection: Posts,\n type: 'many',\n autoremove: true\n }\n});\n```\n\nBe careful with this one! \nWhen Member document is deleted, all posts will be deleted.\n\nThis works from direct and inversed side as well. Use with caution.\n\nIndexing\n--------\n\n```js\nMembers.addLinks({\n 'posts': {\n collection: Posts,\n type: 'many',\n index: true\n }\n});\n```\n\n\n{% pullquote 'warning' %}\nBy using *index: true* option, it will call _ensureIndex automatically on your collection.\nThis will give you a performance boost when you are searching from the \"related\" link, in our case, from \"Posts\".\n{% endpullquote %}\n\n\n","date":"2016-11-29T09:19:02.972Z","updated":"2016-11-29T09:19:02.968Z","path":"guide/links.html","_id":"ciu6eeof30000drjxrzpru644","comments":1,"layout":"page","content":"<h2 id=\"Introduction\"><a href=\"#Introduction\" class=\"headerlink\" title=\"Introduction\"></a>Introduction</h2><p>This module is a collection relationship manager, lets you specify linking information between collections, \ngives you ability to easily manipulate these links (like add, remove), and provides an easy way to fetch them.</p>\n<p>In addition to that, you also have the ability create <em>resolver</em> links that can make REST-API calls or link with any type of database.</p>\n<p>When linking MongoDB collections, we support 4 different ways:</p>\n<h4 id=\"One\"><a href=\"#One\" class=\"headerlink\" title=\"One\"></a>One</h4><p>We use this when we want to reference a single Document. For example, a comment has one author. Or a post has one author.</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">// Comment Document</span></div><div class=\"line\">{</div><div class=\"line\"> ...</div><div class=\"line\"> userId: <span class=\"string\">'XXX'</span></div><div class=\"line\">}</div></pre></td></tr></table></figure>\n<h4 id=\"Many\"><a href=\"#Many\" class=\"headerlink\" title=\"Many\"></a>Many</h4><p>We use this when we want to store multiple references to a collection. This can be viewed as a <em>Many-To-Many</em> SQL relationship, but not necessarily.\nFor example, a user may belong in multiple groups:</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">// User Document</span></div><div class=\"line\">{</div><div class=\"line\"> ...</div><div class=\"line\"> groupIds: [<span class=\"string\">'XXX'</span>, <span class=\"string\">'YYY'</span>]</div><div class=\"line\">}</div></pre></td></tr></table></figure>\n<h4 id=\"One-Meta\"><a href=\"#One-Meta\" class=\"headerlink\" title=\"One Meta\"></a>One Meta</h4><p>Meta comes from <em>metadata</em>. This is used when we want to store additional information about the link. \nFor example, if a user belongs to a single group, we want to store the fact that he is an Admin or not.</p>\n<p>This relationship can be emulated in different ways. We could also store via a <em>Many</em> relationship “adminIds” at Group Level.\nThere is no right or wrong. Just choose what’s best fit.</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">// User Document</span></div><div class=\"line\">{</div><div class=\"line\"> ...</div><div class=\"line\"> groupId: {</div><div class=\"line\"> <span class=\"attr\">_id</span>: <span class=\"string\">'XXX'</span>, <span class=\"attr\">isAdmin</span>: <span class=\"literal\">true</span></div><div class=\"line\"> }</div><div class=\"line\">}</div></pre></td></tr></table></figure>\n<h4 id=\"Many-Meta\"><a href=\"#Many-Meta\" class=\"headerlink\" title=\"Many Meta\"></a>Many Meta</h4><p>Same as the scenario in One Meta, but in this case, a user can belong to multiple groups and he can be admin only to some.</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">// User Document</span></div><div class=\"line\">{</div><div class=\"line\"> ...</div><div class=\"line\"> groupIds: [</div><div class=\"line\"> {<span class=\"attr\">_id</span>: <span class=\"string\">'XXX'</span>, <span class=\"attr\">isAdmin</span>: <span class=\"literal\">true</span>},</div><div class=\"line\"> {<span class=\"attr\">_id</span>: <span class=\"string\">'YYY'</span>, <span class=\"attr\">isAdmin</span>: <span class=\"literal\">false</span>}</div><div class=\"line\"> ]</div><div class=\"line\">}</div></pre></td></tr></table></figure>\n<p>To emulate that you can also have done it in Group Document:</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">// Group Document</span></div><div class=\"line\">{</div><div class=\"line\"> ...</div><div class=\"line\"> userIds: [</div><div class=\"line\"> {<span class=\"attr\">_id</span>: <span class=\"string\">'XXX'</span>, <span class=\"attr\">isAdmin</span>: <span class=\"literal\">true</span>},</div><div class=\"line\"> {<span class=\"attr\">_id</span>: <span class=\"string\">'YYY'</span>, <span class=\"attr\">isAdmin</span>: <span class=\"literal\">false</span>},</div><div class=\"line\"> ]</div><div class=\"line\">}</div></pre></td></tr></table></figure>\n<h2 id=\"Our-First-Link\"><a href=\"#Our-First-Link\" class=\"headerlink\" title=\"Our First Link\"></a>Our First Link</h2><p>You have a Comment that is posted by an User. \nWe either store userId at Comment level, or store commentIds at User level.\nThe second one doesn’t make much sense, so we’ll explore the first one.</p>\n<p>If we store “userId” in Comment document. We have a “One” relationship.</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">// comment document would look like:</span></div><div class=\"line\">{</div><div class=\"line\"> <span class=\"attr\">_id</span>: <span class=\"string\">'XXXXXXXXXXXXXXX'</span>,</div><div class=\"line\"> <span class=\"attr\">text</span>: <span class=\"string\">'Hello Grapher!'</span>,</div><div class=\"line\"> <span class=\"attr\">userId</span>: <span class=\"string\">'XXXXXXXXXXXXXXX'</span></div><div class=\"line\">}</div></pre></td></tr></table></figure>\n<p>To create this kind of link we would do:\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">const</span> Users = Meteor.users;</div><div class=\"line\"><span class=\"keyword\">const</span> Comments = <span class=\"keyword\">new</span> Mongo.Collection(<span class=\"string\">'comments'</span>);</div><div class=\"line\"></div><div class=\"line\">Comments.addLinks({</div><div class=\"line\"> <span class=\"attr\">user</span>: { <span class=\"comment\">// user represents the link name, can be any name you wish</span></div><div class=\"line\"> type: <span class=\"string\">'one'</span>, <span class=\"comment\">// we would have used 'many' if we wanted to store multiple user ids</span></div><div class=\"line\"> collection: Users,</div><div class=\"line\"> <span class=\"attr\">field</span>: <span class=\"string\">'userId'</span> <span class=\"comment\">// optional, if not specified it will generate a specific field.</span></div><div class=\"line\"> }</div><div class=\"line\">});</div></pre></td></tr></table></figure></p>\n<p>We will use the <em>getLink</em> method, which is an object that allows us to fetch, and modify the linked elements.</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">const</span> commentId = Comments.insert({<span class=\"attr\">text</span>: <span class=\"string\">'Our first linked comment.'</span>});</div><div class=\"line\"><span class=\"keyword\">const</span> userLink = Comments.getLink(commentId, <span class=\"string\">'user'</span>); <span class=\"comment\">// we retrieve the link object for commentId and 'user'</span></div><div class=\"line\"></div><div class=\"line\"><span class=\"comment\">// if you have the comment object with an _id, you can also do Comments.getLink(comment, 'user')</span></div><div class=\"line\">userLink.set(<span class=\"keyword\">this</span>.userId); <span class=\"comment\">// will update userId</span></div><div class=\"line\">userLink.unset(); <span class=\"comment\">// will make userId null</span></div><div class=\"line\"></div><div class=\"line\">userLink.fetch(); <span class=\"comment\">// returns the user object, if it was a multi relationship it would have returned an array</span></div><div class=\"line\">userLink.find(); <span class=\"comment\">// returns a Mongo.Cursor, but if you run .fetch() on it will return an array regardless of the relationship type.</span></div><div class=\"line\"></div><div class=\"line\"><span class=\"comment\">// set/unset makes an update immediately into the database, should be run server side.</span></div></pre></td></tr></table></figure>\n<blockquote class=\"pullquote warning\"><p>Removing/unsetting the link, will not affect the related document. If you want to remove it from the database, you will have to do it manually.</p>\n</blockquote>\n<h2 id=\"Inversed-Links\"><a href=\"#Inversed-Links\" class=\"headerlink\" title=\"Inversed Links\"></a>Inversed Links</h2><p>All good but I may want at the user level to fetch all my comments I posted. This is where we introduce the concept of <em>inversed links</em>.\nAn <em>inversed link</em> basically means that the information about the link is stored on the other side. In our case, in the Comment document.</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div></pre></td><td class=\"code\"><pre><div class=\"line\">Users.addLinks({</div><div class=\"line\"> <span class=\"string\">'comments'</span>: {</div><div class=\"line\"> <span class=\"attr\">collection</span>: Comments,</div><div class=\"line\"> <span class=\"attr\">inversedBy</span>: <span class=\"string\">'user'</span></div><div class=\"line\"> }</div><div class=\"line\">});</div><div class=\"line\"></div><div class=\"line\"><span class=\"keyword\">let</span> comments = [];</div><div class=\"line\"><span class=\"keyword\">const</span> commentsLink = Users.getLink(<span class=\"keyword\">this</span>.userId, <span class=\"string\">'comments'</span>);</div><div class=\"line\">comments = commentsLink.find().fetch()</div><div class=\"line\"><span class=\"comment\">// or</span></div><div class=\"line\">comments = commentsLink.fetch()</div><div class=\"line\"><span class=\"comment\">// or filter your query even more using find(filters, options)</span></div><div class=\"line\">comments = commentsLink.find({<span class=\"attr\">text</span>: <span class=\"string\">'Our first linked comment.'</span>}, {<span class=\"attr\">limit</span>: <span class=\"number\">10</span>}).fetch()</div><div class=\"line\"><span class=\"comment\">// or</span></div><div class=\"line\">comments = commentsLink.fetch({<span class=\"attr\">text</span>: <span class=\"string\">'Our first linked comment.'</span>}, {<span class=\"attr\">limit</span>: <span class=\"number\">10</span>})</div></pre></td></tr></table></figure>\n<blockquote class=\"pullquote warning\"><p>If you use filters when fetching from a link, the filters will be applied only for the linked documents.</p>\n</blockquote>\n<p>Now, let’s continue our journey and assume the comment might have different tags. \nSo let’s use a <em>Many</em> relationship:</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div></pre></td><td class=\"code\"><pre><div class=\"line\">Comments.addLinks({</div><div class=\"line\"> <span class=\"attr\">tags</span>: {</div><div class=\"line\"> <span class=\"attr\">collection</span>: Tags,</div><div class=\"line\"> <span class=\"attr\">type</span>: <span class=\"string\">'many'</span></div><div class=\"line\"> }</div><div class=\"line\">})</div><div class=\"line\"></div><div class=\"line\"><span class=\"keyword\">const</span> tagLink = Comments.getLink(commentId, <span class=\"string\">'tags'</span>);</div><div class=\"line\">tagLink.add(tagId);</div><div class=\"line\">tagLink.add(tagObject); <span class=\"comment\">// object must contain _id to be able to identify it, </span></div><div class=\"line\"></div><div class=\"line\"><span class=\"comment\">// IMPORTANT: if the object does not contain _id, the object will be created in the database for you automatically</span></div><div class=\"line\">tagLink.add({<span class=\"attr\">name</span>: <span class=\"string\">'New Tag'</span>}) <span class=\"comment\">// will create a tag document in Tags collection</span></div><div class=\"line\"></div><div class=\"line\"><span class=\"comment\">// Also supports:</span></div><div class=\"line\">tagLink.add([tagId1, tagId2]);</div><div class=\"line\">tagLink.add([tagObject1, tagObject2]);</div><div class=\"line\"></div><div class=\"line\"><span class=\"comment\">// Same arguments are supported by tagLink.remove(...)</span></div></pre></td></tr></table></figure>\n<p>Keep in mind:\nFor single relationships <em>One</em> and <em>One Meta</em> we use set() and unset().\nFor many relationships <em>Many</em> and <em>Many Meta</em> we use add() and remove().</p>\n<h4 id=\"Chain-commands-that-run-updates-easily\"><a href=\"#Chain-commands-that-run-updates-easily\" class=\"headerlink\" title=\"Chain commands that run updates easily:\"></a>Chain commands that run updates easily:</h4><figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div></pre></td><td class=\"code\"><pre><div class=\"line\">tagLink.remove(oldTagId).add(newTagId);</div><div class=\"line\">exampleLink.set(<span class=\"string\">'XXX'</span>).unset();</div></pre></td></tr></table></figure>\n<h2 id=\"Meta-Links\"><a href=\"#Meta-Links\" class=\"headerlink\" title=\"Meta Links\"></a>Meta Links</h2><p>A meta relationship is very useful because you may need to store information <em>about the relationship</em>. \nSuch as an user can belong to certain groups, but he is an admin only to some group</p>\n<p>So instead of creating a separate collection for this, or poluting the groups document, we could use meta relationships.</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div></pre></td><td class=\"code\"><pre><div class=\"line\">Users.addLinks({</div><div class=\"line\"> <span class=\"attr\">groups</span>: {</div><div class=\"line\"> <span class=\"attr\">type</span>: <span class=\"string\">'many'</span></div><div class=\"line\"> metadata: {} <span class=\"comment\">// it is enough to specify metadata as an empty object to make it clear we are dealing with a meta relation</span></div><div class=\"line\"> }</div><div class=\"line\">});</div><div class=\"line\"></div><div class=\"line\"><span class=\"keyword\">const</span> groupsLink = Users.getLink(userId, <span class=\"string\">'groups'</span>);</div><div class=\"line\">groupsLink.add(groupId, {<span class=\"attr\">isAdmin</span>: <span class=\"literal\">true</span>});</div><div class=\"line\"></div><div class=\"line\"><span class=\"comment\">// metadata getter</span></div><div class=\"line\">groupsLink.metadata(groupId) <span class=\"comment\">// returns {isAdmin: true, _id: groupId}}</span></div><div class=\"line\"><span class=\"comment\">// metadata setter</span></div><div class=\"line\">groupsLink.metadata(groupId, {<span class=\"attr\">isAdmin</span>: <span class=\"literal\">false</span>}) <span class=\"comment\">// runs the update for you automatically</span></div></pre></td></tr></table></figure>\n<p>The same principles apply to <em>One Meta</em> relationships, but you don’t need to specify the _id:</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div></pre></td><td class=\"code\"><pre><div class=\"line\">Users.addLinks({</div><div class=\"line\"> <span class=\"attr\">group</span>: {<span class=\"attr\">type</span>: <span class=\"string\">'one'</span>, <span class=\"attr\">metadata</span>: {}}</div><div class=\"line\">})</div><div class=\"line\"></div><div class=\"line\"><span class=\"keyword\">const</span> groupLink = Users.getLink(userId, <span class=\"string\">'group'</span>);</div><div class=\"line\">groupLink.set(groupId, {<span class=\"attr\">isAdmin</span>: <span class=\"literal\">true</span>});</div><div class=\"line\">groupLink.metadata() <span class=\"comment\">// returns {isAdmin: true, _id: groupId}}</span></div><div class=\"line\">groupLink.metadata({<span class=\"attr\">isAdmin</span>: <span class=\"literal\">false</span>}) <span class=\"comment\">// runs the update in the database.</span></div></pre></td></tr></table></figure>\n<h2 id=\"Meta-filters\"><a href=\"#Meta-filters\" class=\"headerlink\" title=\"Meta filters\"></a>Meta filters</h2><p>Given a relationship between 2 entities: Users and Groups\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div></pre></td><td class=\"code\"><pre><div class=\"line\">Users.addLinks({</div><div class=\"line\"> <span class=\"attr\">groups</span>: {</div><div class=\"line\"> <span class=\"attr\">collection</span>: Groups,</div><div class=\"line\"> <span class=\"attr\">type</span>: <span class=\"string\">'many'</span>,</div><div class=\"line\"> <span class=\"attr\">metadata</span>: {</div><div class=\"line\"> <span class=\"attr\">isAdmin</span>: { <span class=\"attr\">type</span>: <span class=\"built_in\">Boolean</span> }</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\">})</div></pre></td></tr></table></figure></p>\n<p>You can now fetch only the groups you are admin to like this:</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">const</span> groupsLink = Users.getLink(userId, <span class=\"string\">'groups'</span>);</div><div class=\"line\">groupsLink.fetch({<span class=\"attr\">$meta</span>: {<span class=\"attr\">isAdmin</span>: <span class=\"literal\">true</span>}});</div></pre></td></tr></table></figure>\n<p>It also works from the inversed side as well:\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div></pre></td><td class=\"code\"><pre><div class=\"line\">Groups.addLinks({</div><div class=\"line\"> <span class=\"attr\">users</span>: {</div><div class=\"line\"> <span class=\"attr\">collection</span>: Users,</div><div class=\"line\"> <span class=\"attr\">inversedBy</span>: <span class=\"string\">'groups'</span></div><div class=\"line\"> }</div><div class=\"line\">})</div><div class=\"line\"></div><div class=\"line\"></div><div class=\"line\"><span class=\"keyword\">const</span> usersLink = Groups.getLink(groupId, <span class=\"string\">'users'</span>);</div><div class=\"line\">usersLink.fetch({<span class=\"attr\">$meta</span>: {<span class=\"attr\">isAdmin</span>: <span class=\"literal\">true</span>}});</div></pre></td></tr></table></figure></p>\n<blockquote class=\"pullquote warning\"><p>Meta filters also works with Query</p>\n</blockquote>\n<h2 id=\"Link-Loopback\"><a href=\"#Link-Loopback\" class=\"headerlink\" title=\"Link Loopback\"></a>Link Loopback</h2><p>Reference the same collection in the link. For tree-like database structures this is great.</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div></pre></td><td class=\"code\"><pre><div class=\"line\">Users.addLinks({</div><div class=\"line\"> <span class=\"attr\">children</span>: {</div><div class=\"line\"> <span class=\"attr\">collection</span>: Users,</div><div class=\"line\"> <span class=\"attr\">type</span>: <span class=\"string\">'many'</span></div><div class=\"line\"> }</div><div class=\"line\"> parent: {</div><div class=\"line\"> <span class=\"attr\">collection</span>: Users,</div><div class=\"line\"> <span class=\"attr\">inversedBy</span>: <span class=\"string\">'children'</span></div><div class=\"line\"> }</div><div class=\"line\">})</div></pre></td></tr></table></figure>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">const</span> childrenLink = Users.getLink(<span class=\"keyword\">this</span>.userId, <span class=\"string\">'children'</span>);</div><div class=\"line\">childrenLink.fetch() <span class=\"comment\">// array of ob</span></div><div class=\"line\"><span class=\"keyword\">const</span> parentLink = Users.getLink(<span class=\"keyword\">this</span>.userId, <span class=\"string\">'children'</span>);</div><div class=\"line\">parentLink.fetch() <span class=\"comment\">// single object</span></div></pre></td></tr></table></figure>\n<h2 id=\"Resolver-Links\"><a href=\"#Resolver-Links\" class=\"headerlink\" title=\"Resolver Links\"></a>Resolver Links</h2><figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div></pre></td><td class=\"code\"><pre><div class=\"line\">Users.addLinks({</div><div class=\"line\"> <span class=\"attr\">tickets</span>: {</div><div class=\"line\"> resolver(user, arg1, arg2) { <span class=\"comment\">// first argument will be the parent, next arguments are what is passed in fetch() or find()</span></div><div class=\"line\"> <span class=\"keyword\">const</span> runner = Meteor.wrapAsync(HTTP.call);</div><div class=\"line\"> <span class=\"keyword\">return</span> runner(<span class=\"string\">\"GET\"</span>, <span class=\"string\">\"https://api.example.com/tickets\"</span>, {<span class=\"attr\">id</span>: user.exampleApiId});</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\">});</div><div class=\"line\"></div><div class=\"line\"><span class=\"keyword\">const</span> ticketLink = Users.getLink(<span class=\"keyword\">this</span>.userId, <span class=\"string\">'tickets'</span>);</div><div class=\"line\">ticketsLink.fetch(arg1, arg2);</div><div class=\"line\">ticketsLink.find(arg1, arg2); <span class=\"comment\">// fetch() and find() they are equivalent for Resolver Links</span></div></pre></td></tr></table></figure>\n<blockquote class=\"pullquote warning\"><p>You must use a sync function for this to work. Read more about <a href=\"https://docs.meteor.com/api/core.html#Meteor-wrapAsync\" target=\"_blank\" rel=\"external\">Meteor.wrapAsync</a>.</p>\n</blockquote>\n<blockquote class=\"pullquote info\"><p>You can also use resolver for special database queries for example, you may need to get only the messages that he has not seen yet.</p>\n</blockquote>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div></pre></td><td class=\"code\"><pre><div class=\"line\">Users.addLinks({</div><div class=\"line\"> <span class=\"attr\">unreadMessages</span>: {</div><div class=\"line\"> resolve(user) {</div><div class=\"line\"> <span class=\"keyword\">return</span> Messages.find({<span class=\"attr\">receiverId</span>: user._id, <span class=\"attr\">isRead</span>: <span class=\"literal\">false</span>}).fetch();</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\">});</div></pre></td></tr></table></figure>\n<h2 id=\"SimpleSchema\"><a href=\"#SimpleSchema\" class=\"headerlink\" title=\"SimpleSchema\"></a>SimpleSchema</h2><p>It is very likely that you would use SimpleSchema to ensure a data-structure for your documents, and prevent bad data to be inserted.\nThis library automatically detects whether you have a schema attached to your collection or not, and will add fields with proper schema definitions.</p>\n<p>IMPORTANT! In order for this to work without problems, make sure your schema is attached before defining links. These are the appended schemas by link type.</p>\n<h4 id=\"One-Relationships\"><a href=\"#One-Relationships\" class=\"headerlink\" title=\"One Relationships\"></a>One Relationships</h4><figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div></pre></td><td class=\"code\"><pre><div class=\"line\">fieldName: {</div><div class=\"line\"> <span class=\"attr\">type</span>: <span class=\"built_in\">String</span>,</div><div class=\"line\"> <span class=\"attr\">optional</span>: <span class=\"literal\">true</span></div><div class=\"line\">}</div></pre></td></tr></table></figure>\n<h4 id=\"Many-Relationships\"><a href=\"#Many-Relationships\" class=\"headerlink\" title=\"Many Relationships\"></a>Many Relationships</h4><figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div></pre></td><td class=\"code\"><pre><div class=\"line\">fieldName: {</div><div class=\"line\"> <span class=\"attr\">type</span>: [<span class=\"built_in\">String</span>], </div><div class=\"line\"> <span class=\"attr\">optional</span>: <span class=\"literal\">true</span></div><div class=\"line\">}</div></pre></td></tr></table></figure>\n<h4 id=\"Meta-Relationships\"><a href=\"#Meta-Relationships\" class=\"headerlink\" title=\"Meta Relationships\"></a>Meta Relationships</h4><p>For meta relationships, it creates a blackbox schema if the metadata option contains no keys</p>\n<p>Example:\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div></pre></td><td class=\"code\"><pre><div class=\"line\">Users.addLinks({</div><div class=\"line\"> <span class=\"attr\">group</span>: {</div><div class=\"line\"> <span class=\"attr\">type</span>: <span class=\"string\">'one'</span>, </div><div class=\"line\"> <span class=\"attr\">field</span>: <span class=\"string\">'groupId'</span>,</div><div class=\"line\"> <span class=\"attr\">metadata</span>: {}</div><div class=\"line\"> }</div><div class=\"line\">});</div></pre></td></tr></table></figure></p>\n<p>This will append to your schema:\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div></pre></td><td class=\"code\"><pre><div class=\"line\">groupId: {</div><div class=\"line\"> <span class=\"attr\">type</span>: <span class=\"built_in\">Object</span>,</div><div class=\"line\"> <span class=\"attr\">blackbox</span>: <span class=\"literal\">true</span>, </div><div class=\"line\"> <span class=\"attr\">optional</span>: <span class=\"literal\">true</span></div><div class=\"line\">}</div></pre></td></tr></table></figure></p>\n<p>Example:\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div></pre></td><td class=\"code\"><pre><div class=\"line\">Users.addLinks({</div><div class=\"line\"> <span class=\"attr\">group</span>: {</div><div class=\"line\"> <span class=\"attr\">type</span>: <span class=\"string\">'one'</span>, </div><div class=\"line\"> <span class=\"attr\">field</span>: <span class=\"string\">'groupId'</span>,</div><div class=\"line\"> <span class=\"attr\">metadata</span>: {</div><div class=\"line\"> <span class=\"attr\">isAdmin</span>: {<span class=\"attr\">type</span>: <span class=\"built_in\">Boolean</span>, <span class=\"attr\">optional</span>: <span class=\"literal\">true</span>}</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\">});</div></pre></td></tr></table></figure></p>\n<p>This will append to your schema:\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div></pre></td><td class=\"code\"><pre><div class=\"line\">groupId: {</div><div class=\"line\"> <span class=\"attr\">type</span>: <span class=\"built_in\">Object</span>,</div><div class=\"line\"> <span class=\"attr\">blackbox</span>: <span class=\"literal\">true</span>, </div><div class=\"line\"> <span class=\"attr\">optional</span>: <span class=\"literal\">true</span></div><div class=\"line\">}</div><div class=\"line\">groupId.$._id: {<span class=\"attr\">type</span>: <span class=\"built_in\">String</span>}</div><div class=\"line\">groupId.$.isAdmin: {<span class=\"attr\">type</span>: <span class=\"built_in\">Boolean</span>, <span class=\"attr\">optional</span>: <span class=\"literal\">true</span>}</div></pre></td></tr></table></figure></p>\n<blockquote class=\"pullquote warning\"><p>_id field is put by default.</p>\n</blockquote>\n<p>If you have a many meta relationship:\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">const</span> metadataSchema = {</div><div class=\"line\"> <span class=\"attr\">_id</span>: {<span class=\"attr\">type</span>: <span class=\"built_in\">String</span>},</div><div class=\"line\"> <span class=\"attr\">isAdmin</span>: {<span class=\"attr\">type</span>: <span class=\"built_in\">Boolean</span>, <span class=\"attr\">optional</span>: <span class=\"literal\">true</span>}</div><div class=\"line\">}</div></pre></td></tr></table></figure></p>\n<p>Appended schema will look like:\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div></pre></td><td class=\"code\"><pre><div class=\"line\">groupIds: {</div><div class=\"line\"> <span class=\"attr\">type</span>: [metadataSchema],</div><div class=\"line\"> <span class=\"attr\">optional</span>: <span class=\"literal\">true</span></div><div class=\"line\">}</div></pre></td></tr></table></figure></p>\n<h2 id=\"Data-Consistency\"><a href=\"#Data-Consistency\" class=\"headerlink\" title=\"Data Consistency\"></a>Data Consistency</h2><p>Let’s say I have a “Thread” with multiple “Members”. If a “Member” is deleted from the database, we don’t want to keep unexisting references.\nThis is why if we delete a member, thread document should be cleaned.</p>\n<blockquote class=\"pullquote warning\"><p>This works for any kind of relationship.</p>\n</blockquote>\n<p>This is achieved by using <a href=\"https://atmospherejs.com/matb33/collection-hooks\" target=\"_blank\" rel=\"external\">https://atmospherejs.com/matb33/collection-hooks</a> package.\nAnd it only works if Member contains the inversed link to Thread.</p>\n<p>Let’s see how that works’</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div></pre></td><td class=\"code\"><pre><div class=\"line\">Threads.addLinks({</div><div class=\"line\"> <span class=\"string\">'members'</span>: {</div><div class=\"line\"> <span class=\"attr\">collection</span>: Members,</div><div class=\"line\"> <span class=\"attr\">type</span>: <span class=\"string\">'many'</span></div><div class=\"line\"> }</div><div class=\"line\">});</div><div class=\"line\"></div><div class=\"line\">Members.addLinks({</div><div class=\"line\"> <span class=\"string\">'threads'</span>: {</div><div class=\"line\"> <span class=\"attr\">collection</span>: Threads,</div><div class=\"line\"> <span class=\"attr\">inversedBy</span>: <span class=\"string\">'members'</span></div><div class=\"line\"> }</div><div class=\"line\">});</div></pre></td></tr></table></figure>\n<p>When <em>Member</em> is removed from the database, it will look for all the threads of that member.\nAnd it will remove it from the fieldStorage. This way your data will be <em>consistent</em> without having to deal with it.</p>\n<h2 id=\"Autoremoval\"><a href=\"#Autoremoval\" class=\"headerlink\" title=\"Autoremoval\"></a>Autoremoval</h2><figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div></pre></td><td class=\"code\"><pre><div class=\"line\">Members.addLinks({</div><div class=\"line\"> <span class=\"string\">'posts'</span>: {</div><div class=\"line\"> <span class=\"attr\">collection</span>: Posts,</div><div class=\"line\"> <span class=\"attr\">type</span>: <span class=\"string\">'many'</span>,</div><div class=\"line\"> <span class=\"attr\">autoremove</span>: <span class=\"literal\">true</span></div><div class=\"line\"> }</div><div class=\"line\">});</div></pre></td></tr></table></figure>\n<p>Be careful with this one! \nWhen Member document is deleted, all posts will be deleted.</p>\n<p>This works from direct and inversed side as well. Use with caution.</p>\n<h2 id=\"Indexing\"><a href=\"#Indexing\" class=\"headerlink\" title=\"Indexing\"></a>Indexing</h2><figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div></pre></td><td class=\"code\"><pre><div class=\"line\">Members.addLinks({</div><div class=\"line\"> <span class=\"string\">'posts'</span>: {</div><div class=\"line\"> <span class=\"attr\">collection</span>: Posts,</div><div class=\"line\"> <span class=\"attr\">type</span>: <span class=\"string\">'many'</span>,</div><div class=\"line\"> <span class=\"attr\">index</span>: <span class=\"literal\">true</span></div><div class=\"line\"> }</div><div class=\"line\">});</div></pre></td></tr></table></figure>\n<blockquote class=\"pullquote warning\"><p>By using <em>index: true</em> option, it will call _ensureIndex automatically on your collection.\nThis will give you a performance boost when you are searching from the “related” link, in our case, from “Posts”.</p>\n</blockquote>\n","excerpt":"","more":"<h2 id=\"Introduction\"><a href=\"#Introduction\" class=\"headerlink\" title=\"Introduction\"></a>Introduction</h2><p>This module is a collection relationship manager, lets you specify linking information between collections, \ngives you ability to easily manipulate these links (like add, remove), and provides an easy way to fetch them.</p>\n<p>In addition to that, you also have the ability create <em>resolver</em> links that can make REST-API calls or link with any type of database.</p>\n<p>When linking MongoDB collections, we support 4 different ways:</p>\n<h4 id=\"One\"><a href=\"#One\" class=\"headerlink\" title=\"One\"></a>One</h4><p>We use this when we want to reference a single Document. For example, a comment has one author. Or a post has one author.</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">// Comment Document</span></div><div class=\"line\">{</div><div class=\"line\"> ...</div><div class=\"line\"> userId: <span class=\"string\">'XXX'</span></div><div class=\"line\">}</div></pre></td></tr></table></figure>\n<h4 id=\"Many\"><a href=\"#Many\" class=\"headerlink\" title=\"Many\"></a>Many</h4><p>We use this when we want to store multiple references to a collection. This can be viewed as a <em>Many-To-Many</em> SQL relationship, but not necessarily.\nFor example, a user may belong in multiple groups:</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">// User Document</span></div><div class=\"line\">{</div><div class=\"line\"> ...</div><div class=\"line\"> groupIds: [<span class=\"string\">'XXX'</span>, <span class=\"string\">'YYY'</span>]</div><div class=\"line\">}</div></pre></td></tr></table></figure>\n<h4 id=\"One-Meta\"><a href=\"#One-Meta\" class=\"headerlink\" title=\"One Meta\"></a>One Meta</h4><p>Meta comes from <em>metadata</em>. This is used when we want to store additional information about the link. \nFor example, if a user belongs to a single group, we want to store the fact that he is an Admin or not.</p>\n<p>This relationship can be emulated in different ways. We could also store via a <em>Many</em> relationship “adminIds” at Group Level.\nThere is no right or wrong. Just choose what’s best fit.</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">// User Document</span></div><div class=\"line\">{</div><div class=\"line\"> ...</div><div class=\"line\"> groupId: {</div><div class=\"line\"> <span class=\"attr\">_id</span>: <span class=\"string\">'XXX'</span>, <span class=\"attr\">isAdmin</span>: <span class=\"literal\">true</span></div><div class=\"line\"> }</div><div class=\"line\">}</div></pre></td></tr></table></figure>\n<h4 id=\"Many-Meta\"><a href=\"#Many-Meta\" class=\"headerlink\" title=\"Many Meta\"></a>Many Meta</h4><p>Same as the scenario in One Meta, but in this case, a user can belong to multiple groups and he can be admin only to some.</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">// User Document</span></div><div class=\"line\">{</div><div class=\"line\"> ...</div><div class=\"line\"> groupIds: [</div><div class=\"line\"> {<span class=\"attr\">_id</span>: <span class=\"string\">'XXX'</span>, <span class=\"attr\">isAdmin</span>: <span class=\"literal\">true</span>},</div><div class=\"line\"> {<span class=\"attr\">_id</span>: <span class=\"string\">'YYY'</span>, <span class=\"attr\">isAdmin</span>: <span class=\"literal\">false</span>}</div><div class=\"line\"> ]</div><div class=\"line\">}</div></pre></td></tr></table></figure>\n<p>To emulate that you can also have done it in Group Document:</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">// Group Document</span></div><div class=\"line\">{</div><div class=\"line\"> ...</div><div class=\"line\"> userIds: [</div><div class=\"line\"> {<span class=\"attr\">_id</span>: <span class=\"string\">'XXX'</span>, <span class=\"attr\">isAdmin</span>: <span class=\"literal\">true</span>},</div><div class=\"line\"> {<span class=\"attr\">_id</span>: <span class=\"string\">'YYY'</span>, <span class=\"attr\">isAdmin</span>: <span class=\"literal\">false</span>},</div><div class=\"line\"> ]</div><div class=\"line\">}</div></pre></td></tr></table></figure>\n<h2 id=\"Our-First-Link\"><a href=\"#Our-First-Link\" class=\"headerlink\" title=\"Our First Link\"></a>Our First Link</h2><p>You have a Comment that is posted by an User. \nWe either store userId at Comment level, or store commentIds at User level.\nThe second one doesn’t make much sense, so we’ll explore the first one.</p>\n<p>If we store “userId” in Comment document. We have a “One” relationship.</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">// comment document would look like:</span></div><div class=\"line\">{</div><div class=\"line\"> <span class=\"attr\">_id</span>: <span class=\"string\">'XXXXXXXXXXXXXXX'</span>,</div><div class=\"line\"> <span class=\"attr\">text</span>: <span class=\"string\">'Hello Grapher!'</span>,</div><div class=\"line\"> <span class=\"attr\">userId</span>: <span class=\"string\">'XXXXXXXXXXXXXXX'</span></div><div class=\"line\">}</div></pre></td></tr></table></figure>\n<p>To create this kind of link we would do:\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">const</span> Users = Meteor.users;</div><div class=\"line\"><span class=\"keyword\">const</span> Comments = <span class=\"keyword\">new</span> Mongo.Collection(<span class=\"string\">'comments'</span>);</div><div class=\"line\"></div><div class=\"line\">Comments.addLinks({</div><div class=\"line\"> <span class=\"attr\">user</span>: { <span class=\"comment\">// user represents the link name, can be any name you wish</span></div><div class=\"line\"> type: <span class=\"string\">'one'</span>, <span class=\"comment\">// we would have used 'many' if we wanted to store multiple user ids</span></div><div class=\"line\"> collection: Users,</div><div class=\"line\"> <span class=\"attr\">field</span>: <span class=\"string\">'userId'</span> <span class=\"comment\">// optional, if not specified it will generate a specific field.</span></div><div class=\"line\"> }</div><div class=\"line\">});</div></pre></td></tr></table></figure></p>\n<p>We will use the <em>getLink</em> method, which is an object that allows us to fetch, and modify the linked elements.</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">const</span> commentId = Comments.insert({<span class=\"attr\">text</span>: <span class=\"string\">'Our first linked comment.'</span>});</div><div class=\"line\"><span class=\"keyword\">const</span> userLink = Comments.getLink(commentId, <span class=\"string\">'user'</span>); <span class=\"comment\">// we retrieve the link object for commentId and 'user'</span></div><div class=\"line\"></div><div class=\"line\"><span class=\"comment\">// if you have the comment object with an _id, you can also do Comments.getLink(comment, 'user')</span></div><div class=\"line\">userLink.set(<span class=\"keyword\">this</span>.userId); <span class=\"comment\">// will update userId</span></div><div class=\"line\">userLink.unset(); <span class=\"comment\">// will make userId null</span></div><div class=\"line\"></div><div class=\"line\">userLink.fetch(); <span class=\"comment\">// returns the user object, if it was a multi relationship it would have returned an array</span></div><div class=\"line\">userLink.find(); <span class=\"comment\">// returns a Mongo.Cursor, but if you run .fetch() on it will return an array regardless of the relationship type.</span></div><div class=\"line\"></div><div class=\"line\"><span class=\"comment\">// set/unset makes an update immediately into the database, should be run server side.</span></div></pre></td></tr></table></figure>\n<blockquote class=\"pullquote warning\"><p>Removing/unsetting the link, will not affect the related document. If you want to remove it from the database, you will have to do it manually.</p>\n</blockquote>\n<h2 id=\"Inversed-Links\"><a href=\"#Inversed-Links\" class=\"headerlink\" title=\"Inversed Links\"></a>Inversed Links</h2><p>All good but I may want at the user level to fetch all my comments I posted. This is where we introduce the concept of <em>inversed links</em>.\nAn <em>inversed link</em> basically means that the information about the link is stored on the other side. In our case, in the Comment document.</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div></pre></td><td class=\"code\"><pre><div class=\"line\">Users.addLinks({</div><div class=\"line\"> <span class=\"string\">'comments'</span>: {</div><div class=\"line\"> <span class=\"attr\">collection</span>: Comments,</div><div class=\"line\"> <span class=\"attr\">inversedBy</span>: <span class=\"string\">'user'</span></div><div class=\"line\"> }</div><div class=\"line\">});</div><div class=\"line\"></div><div class=\"line\"><span class=\"keyword\">let</span> comments = [];</div><div class=\"line\"><span class=\"keyword\">const</span> commentsLink = Users.getLink(<span class=\"keyword\">this</span>.userId, <span class=\"string\">'comments'</span>);</div><div class=\"line\">comments = commentsLink.find().fetch()</div><div class=\"line\"><span class=\"comment\">// or</span></div><div class=\"line\">comments = commentsLink.fetch()</div><div class=\"line\"><span class=\"comment\">// or filter your query even more using find(filters, options)</span></div><div class=\"line\">comments = commentsLink.find({<span class=\"attr\">text</span>: <span class=\"string\">'Our first linked comment.'</span>}, {<span class=\"attr\">limit</span>: <span class=\"number\">10</span>}).fetch()</div><div class=\"line\"><span class=\"comment\">// or</span></div><div class=\"line\">comments = commentsLink.fetch({<span class=\"attr\">text</span>: <span class=\"string\">'Our first linked comment.'</span>}, {<span class=\"attr\">limit</span>: <span class=\"number\">10</span>})</div></pre></td></tr></table></figure>\n<blockquote class=\"pullquote warning\"><p>If you use filters when fetching from a link, the filters will be applied only for the linked documents.</p>\n</blockquote>\n<p>Now, let’s continue our journey and assume the comment might have different tags. \nSo let’s use a <em>Many</em> relationship:</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div></pre></td><td class=\"code\"><pre><div class=\"line\">Comments.addLinks({</div><div class=\"line\"> <span class=\"attr\">tags</span>: {</div><div class=\"line\"> <span class=\"attr\">collection</span>: Tags,</div><div class=\"line\"> <span class=\"attr\">type</span>: <span class=\"string\">'many'</span></div><div class=\"line\"> }</div><div class=\"line\">})</div><div class=\"line\"></div><div class=\"line\"><span class=\"keyword\">const</span> tagLink = Comments.getLink(commentId, <span class=\"string\">'tags'</span>);</div><div class=\"line\">tagLink.add(tagId);</div><div class=\"line\">tagLink.add(tagObject); <span class=\"comment\">// object must contain _id to be able to identify it, </span></div><div class=\"line\"></div><div class=\"line\"><span class=\"comment\">// IMPORTANT: if the object does not contain _id, the object will be created in the database for you automatically</span></div><div class=\"line\">tagLink.add({<span class=\"attr\">name</span>: <span class=\"string\">'New Tag'</span>}) <span class=\"comment\">// will create a tag document in Tags collection</span></div><div class=\"line\"></div><div class=\"line\"><span class=\"comment\">// Also supports:</span></div><div class=\"line\">tagLink.add([tagId1, tagId2]);</div><div class=\"line\">tagLink.add([tagObject1, tagObject2]);</div><div class=\"line\"></div><div class=\"line\"><span class=\"comment\">// Same arguments are supported by tagLink.remove(...)</span></div></pre></td></tr></table></figure>\n<p>Keep in mind:\nFor single relationships <em>One</em> and <em>One Meta</em> we use set() and unset().\nFor many relationships <em>Many</em> and <em>Many Meta</em> we use add() and remove().</p>\n<h4 id=\"Chain-commands-that-run-updates-easily\"><a href=\"#Chain-commands-that-run-updates-easily\" class=\"headerlink\" title=\"Chain commands that run updates easily:\"></a>Chain commands that run updates easily:</h4><figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div></pre></td><td class=\"code\"><pre><div class=\"line\">tagLink.remove(oldTagId).add(newTagId);</div><div class=\"line\">exampleLink.set(<span class=\"string\">'XXX'</span>).unset();</div></pre></td></tr></table></figure>\n<h2 id=\"Meta-Links\"><a href=\"#Meta-Links\" class=\"headerlink\" title=\"Meta Links\"></a>Meta Links</h2><p>A meta relationship is very useful because you may need to store information <em>about the relationship</em>. \nSuch as an user can belong to certain groups, but he is an admin only to some group</p>\n<p>So instead of creating a separate collection for this, or poluting the groups document, we could use meta relationships.</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div></pre></td><td class=\"code\"><pre><div class=\"line\">Users.addLinks({</div><div class=\"line\"> <span class=\"attr\">groups</span>: {</div><div class=\"line\"> <span class=\"attr\">type</span>: <span class=\"string\">'many'</span></div><div class=\"line\"> metadata: {} <span class=\"comment\">// it is enough to specify metadata as an empty object to make it clear we are dealing with a meta relation</span></div><div class=\"line\"> }</div><div class=\"line\">});</div><div class=\"line\"></div><div class=\"line\"><span class=\"keyword\">const</span> groupsLink = Users.getLink(userId, <span class=\"string\">'groups'</span>);</div><div class=\"line\">groupsLink.add(groupId, {<span class=\"attr\">isAdmin</span>: <span class=\"literal\">true</span>});</div><div class=\"line\"></div><div class=\"line\"><span class=\"comment\">// metadata getter</span></div><div class=\"line\">groupsLink.metadata(groupId) <span class=\"comment\">// returns {isAdmin: true, _id: groupId}}</span></div><div class=\"line\"><span class=\"comment\">// metadata setter</span></div><div class=\"line\">groupsLink.metadata(groupId, {<span class=\"attr\">isAdmin</span>: <span class=\"literal\">false</span>}) <span class=\"comment\">// runs the update for you automatically</span></div></pre></td></tr></table></figure>\n<p>The same principles apply to <em>One Meta</em> relationships, but you don’t need to specify the _id:</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div></pre></td><td class=\"code\"><pre><div class=\"line\">Users.addLinks({</div><div class=\"line\"> <span class=\"attr\">group</span>: {<span class=\"attr\">type</span>: <span class=\"string\">'one'</span>, <span class=\"attr\">metadata</span>: {}}</div><div class=\"line\">})</div><div class=\"line\"></div><div class=\"line\"><span class=\"keyword\">const</span> groupLink = Users.getLink(userId, <span class=\"string\">'group'</span>);</div><div class=\"line\">groupLink.set(groupId, {<span class=\"attr\">isAdmin</span>: <span class=\"literal\">true</span>});</div><div class=\"line\">groupLink.metadata() <span class=\"comment\">// returns {isAdmin: true, _id: groupId}}</span></div><div class=\"line\">groupLink.metadata({<span class=\"attr\">isAdmin</span>: <span class=\"literal\">false</span>}) <span class=\"comment\">// runs the update in the database.</span></div></pre></td></tr></table></figure>\n<h2 id=\"Meta-filters\"><a href=\"#Meta-filters\" class=\"headerlink\" title=\"Meta filters\"></a>Meta filters</h2><p>Given a relationship between 2 entities: Users and Groups\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div></pre></td><td class=\"code\"><pre><div class=\"line\">Users.addLinks({</div><div class=\"line\"> <span class=\"attr\">groups</span>: {</div><div class=\"line\"> <span class=\"attr\">collection</span>: Groups,</div><div class=\"line\"> <span class=\"attr\">type</span>: <span class=\"string\">'many'</span>,</div><div class=\"line\"> <span class=\"attr\">metadata</span>: {</div><div class=\"line\"> <span class=\"attr\">isAdmin</span>: { <span class=\"attr\">type</span>: <span class=\"built_in\">Boolean</span> }</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\">})</div></pre></td></tr></table></figure></p>\n<p>You can now fetch only the groups you are admin to like this:</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">const</span> groupsLink = Users.getLink(userId, <span class=\"string\">'groups'</span>);</div><div class=\"line\">groupsLink.fetch({<span class=\"attr\">$meta</span>: {<span class=\"attr\">isAdmin</span>: <span class=\"literal\">true</span>}});</div></pre></td></tr></table></figure>\n<p>It also works from the inversed side as well:\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div></pre></td><td class=\"code\"><pre><div class=\"line\">Groups.addLinks({</div><div class=\"line\"> <span class=\"attr\">users</span>: {</div><div class=\"line\"> <span class=\"attr\">collection</span>: Users,</div><div class=\"line\"> <span class=\"attr\">inversedBy</span>: <span class=\"string\">'groups'</span></div><div class=\"line\"> }</div><div class=\"line\">})</div><div class=\"line\"></div><div class=\"line\"></div><div class=\"line\"><span class=\"keyword\">const</span> usersLink = Groups.getLink(groupId, <span class=\"string\">'users'</span>);</div><div class=\"line\">usersLink.fetch({<span class=\"attr\">$meta</span>: {<span class=\"attr\">isAdmin</span>: <span class=\"literal\">true</span>}});</div></pre></td></tr></table></figure></p>\n<blockquote class=\"pullquote warning\"><p>Meta filters also works with Query</p>\n</blockquote>\n<h2 id=\"Link-Loopback\"><a href=\"#Link-Loopback\" class=\"headerlink\" title=\"Link Loopback\"></a>Link Loopback</h2><p>Reference the same collection in the link. For tree-like database structures this is great.</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div></pre></td><td class=\"code\"><pre><div class=\"line\">Users.addLinks({</div><div class=\"line\"> <span class=\"attr\">children</span>: {</div><div class=\"line\"> <span class=\"attr\">collection</span>: Users,</div><div class=\"line\"> <span class=\"attr\">type</span>: <span class=\"string\">'many'</span></div><div class=\"line\"> }</div><div class=\"line\"> parent: {</div><div class=\"line\"> <span class=\"attr\">collection</span>: Users,</div><div class=\"line\"> <span class=\"attr\">inversedBy</span>: <span class=\"string\">'children'</span></div><div class=\"line\"> }</div><div class=\"line\">})</div></pre></td></tr></table></figure>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">const</span> childrenLink = Users.getLink(<span class=\"keyword\">this</span>.userId, <span class=\"string\">'children'</span>);</div><div class=\"line\">childrenLink.fetch() <span class=\"comment\">// array of ob</span></div><div class=\"line\"><span class=\"keyword\">const</span> parentLink = Users.getLink(<span class=\"keyword\">this</span>.userId, <span class=\"string\">'children'</span>);</div><div class=\"line\">parentLink.fetch() <span class=\"comment\">// single object</span></div></pre></td></tr></table></figure>\n<h2 id=\"Resolver-Links\"><a href=\"#Resolver-Links\" class=\"headerlink\" title=\"Resolver Links\"></a>Resolver Links</h2><figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div></pre></td><td class=\"code\"><pre><div class=\"line\">Users.addLinks({</div><div class=\"line\"> <span class=\"attr\">tickets</span>: {</div><div class=\"line\"> resolver(user, arg1, arg2) { <span class=\"comment\">// first argument will be the parent, next arguments are what is passed in fetch() or find()</span></div><div class=\"line\"> <span class=\"keyword\">const</span> runner = Meteor.wrapAsync(HTTP.call);</div><div class=\"line\"> <span class=\"keyword\">return</span> runner(<span class=\"string\">\"GET\"</span>, <span class=\"string\">\"https://api.example.com/tickets\"</span>, {<span class=\"attr\">id</span>: user.exampleApiId});</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\">});</div><div class=\"line\"></div><div class=\"line\"><span class=\"keyword\">const</span> ticketLink = Users.getLink(<span class=\"keyword\">this</span>.userId, <span class=\"string\">'tickets'</span>);</div><div class=\"line\">ticketsLink.fetch(arg1, arg2);</div><div class=\"line\">ticketsLink.find(arg1, arg2); <span class=\"comment\">// fetch() and find() they are equivalent for Resolver Links</span></div></pre></td></tr></table></figure>\n<blockquote class=\"pullquote warning\"><p>You must use a sync function for this to work. Read more about <a href=\"https://docs.meteor.com/api/core.html#Meteor-wrapAsync\">Meteor.wrapAsync</a>.</p>\n</blockquote>\n<blockquote class=\"pullquote info\"><p>You can also use resolver for special database queries for example, you may need to get only the messages that he has not seen yet.</p>\n</blockquote>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div></pre></td><td class=\"code\"><pre><div class=\"line\">Users.addLinks({</div><div class=\"line\"> <span class=\"attr\">unreadMessages</span>: {</div><div class=\"line\"> resolve(user) {</div><div class=\"line\"> <span class=\"keyword\">return</span> Messages.find({<span class=\"attr\">receiverId</span>: user._id, <span class=\"attr\">isRead</span>: <span class=\"literal\">false</span>}).fetch();</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\">});</div></pre></td></tr></table></figure>\n<h2 id=\"SimpleSchema\"><a href=\"#SimpleSchema\" class=\"headerlink\" title=\"SimpleSchema\"></a>SimpleSchema</h2><p>It is very likely that you would use SimpleSchema to ensure a data-structure for your documents, and prevent bad data to be inserted.\nThis library automatically detects whether you have a schema attached to your collection or not, and will add fields with proper schema definitions.</p>\n<p>IMPORTANT! In order for this to work without problems, make sure your schema is attached before defining links. These are the appended schemas by link type.</p>\n<h4 id=\"One-Relationships\"><a href=\"#One-Relationships\" class=\"headerlink\" title=\"One Relationships\"></a>One Relationships</h4><figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div></pre></td><td class=\"code\"><pre><div class=\"line\">fieldName: {</div><div class=\"line\"> <span class=\"attr\">type</span>: <span class=\"built_in\">String</span>,</div><div class=\"line\"> <span class=\"attr\">optional</span>: <span class=\"literal\">true</span></div><div class=\"line\">}</div></pre></td></tr></table></figure>\n<h4 id=\"Many-Relationships\"><a href=\"#Many-Relationships\" class=\"headerlink\" title=\"Many Relationships\"></a>Many Relationships</h4><figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div></pre></td><td class=\"code\"><pre><div class=\"line\">fieldName: {</div><div class=\"line\"> <span class=\"attr\">type</span>: [<span class=\"built_in\">String</span>], </div><div class=\"line\"> <span class=\"attr\">optional</span>: <span class=\"literal\">true</span></div><div class=\"line\">}</div></pre></td></tr></table></figure>\n<h4 id=\"Meta-Relationships\"><a href=\"#Meta-Relationships\" class=\"headerlink\" title=\"Meta Relationships\"></a>Meta Relationships</h4><p>For meta relationships, it creates a blackbox schema if the metadata option contains no keys</p>\n<p>Example:\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div></pre></td><td class=\"code\"><pre><div class=\"line\">Users.addLinks({</div><div class=\"line\"> <span class=\"attr\">group</span>: {</div><div class=\"line\"> <span class=\"attr\">type</span>: <span class=\"string\">'one'</span>, </div><div class=\"line\"> <span class=\"attr\">field</span>: <span class=\"string\">'groupId'</span>,</div><div class=\"line\"> <span class=\"attr\">metadata</span>: {}</div><div class=\"line\"> }</div><div class=\"line\">});</div></pre></td></tr></table></figure></p>\n<p>This will append to your schema:\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div></pre></td><td class=\"code\"><pre><div class=\"line\">groupId: {</div><div class=\"line\"> <span class=\"attr\">type</span>: <span class=\"built_in\">Object</span>,</div><div class=\"line\"> <span class=\"attr\">blackbox</span>: <span class=\"literal\">true</span>, </div><div class=\"line\"> <span class=\"attr\">optional</span>: <span class=\"literal\">true</span></div><div class=\"line\">}</div></pre></td></tr></table></figure></p>\n<p>Example:\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div></pre></td><td class=\"code\"><pre><div class=\"line\">Users.addLinks({</div><div class=\"line\"> <span class=\"attr\">group</span>: {</div><div class=\"line\"> <span class=\"attr\">type</span>: <span class=\"string\">'one'</span>, </div><div class=\"line\"> <span class=\"attr\">field</span>: <span class=\"string\">'groupId'</span>,</div><div class=\"line\"> <span class=\"attr\">metadata</span>: {</div><div class=\"line\"> <span class=\"attr\">isAdmin</span>: {<span class=\"attr\">type</span>: <span class=\"built_in\">Boolean</span>, <span class=\"attr\">optional</span>: <span class=\"literal\">true</span>}</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\">});</div></pre></td></tr></table></figure></p>\n<p>This will append to your schema:\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div></pre></td><td class=\"code\"><pre><div class=\"line\">groupId: {</div><div class=\"line\"> <span class=\"attr\">type</span>: <span class=\"built_in\">Object</span>,</div><div class=\"line\"> <span class=\"attr\">blackbox</span>: <span class=\"literal\">true</span>, </div><div class=\"line\"> <span class=\"attr\">optional</span>: <span class=\"literal\">true</span></div><div class=\"line\">}</div><div class=\"line\">groupId.$._id: {<span class=\"attr\">type</span>: <span class=\"built_in\">String</span>}</div><div class=\"line\">groupId.$.isAdmin: {<span class=\"attr\">type</span>: <span class=\"built_in\">Boolean</span>, <span class=\"attr\">optional</span>: <span class=\"literal\">true</span>}</div></pre></td></tr></table></figure></p>\n<blockquote class=\"pullquote warning\"><p>_id field is put by default.</p>\n</blockquote>\n<p>If you have a many meta relationship:\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">const</span> metadataSchema = {</div><div class=\"line\"> <span class=\"attr\">_id</span>: {<span class=\"attr\">type</span>: <span class=\"built_in\">String</span>},</div><div class=\"line\"> <span class=\"attr\">isAdmin</span>: {<span class=\"attr\">type</span>: <span class=\"built_in\">Boolean</span>, <span class=\"attr\">optional</span>: <span class=\"literal\">true</span>}</div><div class=\"line\">}</div></pre></td></tr></table></figure></p>\n<p>Appended schema will look like:\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div></pre></td><td class=\"code\"><pre><div class=\"line\">groupIds: {</div><div class=\"line\"> <span class=\"attr\">type</span>: [metadataSchema],</div><div class=\"line\"> <span class=\"attr\">optional</span>: <span class=\"literal\">true</span></div><div class=\"line\">}</div></pre></td></tr></table></figure></p>\n<h2 id=\"Data-Consistency\"><a href=\"#Data-Consistency\" class=\"headerlink\" title=\"Data Consistency\"></a>Data Consistency</h2><p>Let’s say I have a “Thread” with multiple “Members”. If a “Member” is deleted from the database, we don’t want to keep unexisting references.\nThis is why if we delete a member, thread document should be cleaned.</p>\n<blockquote class=\"pullquote warning\"><p>This works for any kind of relationship.</p>\n</blockquote>\n<p>This is achieved by using <a href=\"https://atmospherejs.com/matb33/collection-hooks\">https://atmospherejs.com/matb33/collection-hooks</a> package.\nAnd it only works if Member contains the inversed link to Thread.</p>\n<p>Let’s see how that works’</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div></pre></td><td class=\"code\"><pre><div class=\"line\">Threads.addLinks({</div><div class=\"line\"> <span class=\"string\">'members'</span>: {</div><div class=\"line\"> <span class=\"attr\">collection</span>: Members,</div><div class=\"line\"> <span class=\"attr\">type</span>: <span class=\"string\">'many'</span></div><div class=\"line\"> }</div><div class=\"line\">});</div><div class=\"line\"></div><div class=\"line\">Members.addLinks({</div><div class=\"line\"> <span class=\"string\">'threads'</span>: {</div><div class=\"line\"> <span class=\"attr\">collection</span>: Threads,</div><div class=\"line\"> <span class=\"attr\">inversedBy</span>: <span class=\"string\">'members'</span></div><div class=\"line\"> }</div><div class=\"line\">});</div></pre></td></tr></table></figure>\n<p>When <em>Member</em> is removed from the database, it will look for all the threads of that member.\nAnd it will remove it from the fieldStorage. This way your data will be <em>consistent</em> without having to deal with it.</p>\n<h2 id=\"Autoremoval\"><a href=\"#Autoremoval\" class=\"headerlink\" title=\"Autoremoval\"></a>Autoremoval</h2><figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div></pre></td><td class=\"code\"><pre><div class=\"line\">Members.addLinks({</div><div class=\"line\"> <span class=\"string\">'posts'</span>: {</div><div class=\"line\"> <span class=\"attr\">collection</span>: Posts,</div><div class=\"line\"> <span class=\"attr\">type</span>: <span class=\"string\">'many'</span>,</div><div class=\"line\"> <span class=\"attr\">autoremove</span>: <span class=\"literal\">true</span></div><div class=\"line\"> }</div><div class=\"line\">});</div></pre></td></tr></table></figure>\n<p>Be careful with this one! \nWhen Member document is deleted, all posts will be deleted.</p>\n<p>This works from direct and inversed side as well. Use with caution.</p>\n<h2 id=\"Indexing\"><a href=\"#Indexing\" class=\"headerlink\" title=\"Indexing\"></a>Indexing</h2><figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div></pre></td><td class=\"code\"><pre><div class=\"line\">Members.addLinks({</div><div class=\"line\"> <span class=\"string\">'posts'</span>: {</div><div class=\"line\"> <span class=\"attr\">collection</span>: Posts,</div><div class=\"line\"> <span class=\"attr\">type</span>: <span class=\"string\">'many'</span>,</div><div class=\"line\"> <span class=\"attr\">index</span>: <span class=\"literal\">true</span></div><div class=\"line\"> }</div><div class=\"line\">});</div></pre></td></tr></table></figure>\n<blockquote class=\"pullquote warning\"><p>By using <em>index: true</em> option, it will call _ensureIndex automatically on your collection.\nThis will give you a performance boost when you are searching from the “related” link, in our case, from “Posts”.</p>\n</blockquote>\n"}],"Post":[],"PostAsset":[],"PostCategory":[],"PostTag":[],"Tag":[]}}