{"__v":41,"_id":"574df07469b8db2400fa421c","category":{"project":"54774d9af3736008009e9e0e","version":"56a0bd9e3697d80d002ac5e7","_id":"5735a52431a73b1700887ca0","__v":0,"sync":{"url":"","isSync":false},"reference":false,"createdAt":"2016-05-13T09:57:56.274Z","from_sync":false,"order":13,"slug":"data-objects","title":"Data Objects"},"parentDoc":null,"project":"54774d9af3736008009e9e0e","user":"54774c47f3736008009e9e0c","version":{"__v":20,"_id":"56a0bd9e3697d80d002ac5e7","project":"54774d9af3736008009e9e0e","createdAt":"2016-01-21T11:14:38.131Z","releaseDate":"2016-01-21T11:14:38.131Z","categories":["56a0bd9f3697d80d002ac5e8","56a0bd9f3697d80d002ac5e9","56a0bd9f3697d80d002ac5ea","56a0bd9f3697d80d002ac5eb","56b098a43a5b810d00745e3f","56b098da8f7a4f0d0029dd10","56d5a8ecf612b80b00fb69cd","570989853ab43c0e0072b2d6","571006aa10300c0e007f6133","5735a52431a73b1700887ca0","5744b0529e045c0e00b7a7a2","5744b1d0b56d431700d8a4fb","5744b1fb55d65a0e00b436e1","5744b218f9c7411700ce560e","5744b220f9c7411700ce560f","5744b2259e045c0e00b7a7a7","5744b22cf8b79f0e00de6a2d","5744b23155d65a0e00b436e4","5744b242c758290e00fbc235","5744b2569e045c0e00b7a7a8","5756a3f2bb92962900dafe3d","57ee23e81e42900e0014a42f","581c822c98676e0f00d240ef"],"is_deprecated":false,"is_hidden":false,"is_beta":false,"is_stable":true,"codename":"Sockets","version_clean":"1.1.0","version":"1.1"},"updates":[],"next":{"pages":[],"description":""},"createdAt":"2016-05-31T20:13:40.310Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":8,"body":"## Chapter contents\n\n1. [Overview](#overview)\n2. [one-to-one relation](#one-to-one-relation)\n3. [one-to-many & many-to-many relations](#one-to-many--many-to-many-relations)\n4. [Filtering on Relation and Reference fields](#filtering-on-relation-and-reference-fields)\n5. [Summary](#summary) \n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Overview\"\n}\n[/block]\nIn Syncano, you can create links between Data Objects called relationships. There are 3 possible options here:\n- `one-to-one` - One Data Object is connected to another.\n- `one-to-many` - One Data Object has relations with many other.\n- `many-to-many` - This type of relation allows for creating a net of connections.\n\nWe will dig into those solutions in the sections below.\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"one-to-one relation\"\n}\n[/block]\none-to-one relationships can come in handy in a situation where one Data Object will need to be split into two. This shouldn't be very common but there are couple of use cases:\n- Limiting access to part of the stored data - In this case Data Objects could be in different Data Classes, where different users would have access to each of these Data Classes. This would allow making only part of the data visible based on permissions.\n- Splitting Data Object because of size limits - Data Object size limit is 32 kB. In case this is not enough you could store rest of the data in a referenced Data Object. In most of cases using a `file` schema field type and storing data there would be a better solution but using a reference will work too.\n\n###  Creating one-to-one reference\n\nTo create a reference you'll need to create a Data Class with a `reference` schema field type (you can read about Data Classes and their schemas [here](doc:classes-overview)). It's a bit different from other schema field types because it has and additional property called `Target Data Class`. In this dropdown you can choose whether referenced Data Objects will be in the same (`self` option) or a different Data Class.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/99d8xDsSImYTbXTHlDQt_class_ref.png\",\n        \"class_ref.png\",\n        \"1438\",\n        \"751\",\n        \"#3476b5\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nOnce you have this set up you can create Data Objects with references. Reference value is the id of a Data Object that will be linked:\n\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"curl -X POST \\\\\\n-H \\\"X-API-KEY: API_KEY\\\" \\\\\\n-H \\\"Content-type: application/json\\\" \\\\\\n-d '{\\\"reference\\\": 1}' \\\\\\n\\\"https://api.syncano.io/v1.1/instances/INSTANCE_NAME/classes/data_class_with_references/objects/\\\"\",\n      \"language\": \"curl\"\n    },\n    {\n      \"code\": \"import syncano\\nfrom syncano.models import Object\\n\\nconnection = syncano.connect(api_key='API_KEY')\\n\\nObject.please.create(\\n  instance_name=\\\"INSTANCE_NAME\\\",\\n  class_name=\\\"class_with_references\\\",\\n  reference=1\\n)\",\n      \"language\": \"python\"\n    },\n    {\n      \"code\": \"var Syncano = require(\\\"syncano\\\");  // CommonJS\\nvar connection = Syncano({accountKey: \\\"ACCOUNT_KEY\\\"});\\nvar DataObject = connection.DataObject;\\n\\nvar ref = {\\n  reference: 1,\\n  instanceName: \\\"INSTANCE_NAME\\\",\\n  className: \\\"class_with_references\\\"\\n};\\n\\nDataObject.please().create(ref).then(function(ref) {\\n  console.log(\\\"reference\\\", ref);\\n});\",\n      \"language\": \"javascript\"\n    },\n    {\n      \"code\": \"ReferenceClass ref = new ReferenceClass();\\nref.setId(1);\\n\\nClassWithReference objectWithRef = new ClassWithReference();\\nobjectWithRef.reference = ref;\\n\\nResponse<ClassWithReference> response = objectWithRef.save();\",\n      \"language\": \"java\",\n      \"name\": \"Android\"\n    },\n    {\n      \"code\": \":::at:::interface Author : SCDataObject\\n@property (nonatomic,retain) NSString *firstName;\\n@property (nonatomic,retain) NSString *secondName;\\n@end\\n\\n@interface Book : SCDataObject\\n@property (nonatomic,retain) NSString *title;\\n@property (nonatomic,retain) NSNumber *numOfPages;\\n@property (nonatomic,retain) Author *author;\\n@end\\n\\n  \\n//creating a Data Object with reference using Reference class\\nAuthor *author = [Author new];\\nauthor.firstName = @\\\"AUTHOR-FIRST-NAME\\\";\\nauthor.secondName = @\\\"AUTHOR-SECOND-NAME\\\";\\n[author saveWithCompletionBlock:^(NSError * _Nullable error) {\\n    if (error == nil) {\\n        Book *book = [Book new];\\n        book.author = author\\n        [book saveWithCompletionBlock:^(NSError * _Nullable error) {\\n            //handle error\\n        }]\\n    }\\n}];\",\n      \"language\": \"objectivec\"\n    },\n    {\n      \"code\": \"class Author: SCDataObject {\\n    var firstName = \\\"\\\"\\n    var secondName = \\\"\\\"\\n    \\n}\\n\\nclass Book: SCDataObject {\\n    var title = \\\"\\\"\\n    var numberOfPages = 0\\n    var author:Author?\\n}\\n\\n//creating a Data Object with reference using Reference class\\nlet author:Author = Author()\\nauthor.firstName = \\\"AUTHOR-FIRST-NAME\\\"\\nauthor.secondName = \\\"AUTHOR-SECOND-NAME\\\"\\nauthor.saveWithCompletionBlock { (error) in\\n    if error == nil {\\n        let book = Book()\\n        book.author = author\\n        book.saveWithCompletionBlock({ (error) in\\n            //handle error\\n        })\\n    }\\n}\",\n      \"language\": \"swift\"\n    },\n    {\n      \"code\": \"require 'syncano'\\n\\nclass_with_reference = instance.classes.find('class_with_reference')\\n\\nclass_with_reference.objects.create(reference: 1)\",\n      \"language\": \"ruby\"\n    },\n    {\n      \"code\": \"// NOT AVAILABLE\",\n      \"language\": \"csharp\",\n      \"name\": \"Unity\"\n    }\n  ]\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"one-to-many & many-to-many relations\"\n}\n[/block]\nTo create `one-to-many` or `many-to-many` relationships you can use Syncano's `relation` field. It's an array where you can store ids of a connected Data Object. So, for example if you had an `Authors` and `Books` data classes you could create a relation field in the `Authors` Data Class. This field could hold an array of Data Object ids representing books from `Books` data class.\n\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/gXYHforbTICxeRuw8e9q_class_relation.png\",\n        \"class_relation.png\",\n        \"2548\",\n        \"1310\",\n        \"#3a79af\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n###  Creating one-to-many and many-to-many relation\n\nOnce you have a proper set up, you can start making Data Objects with relations. This is how it could be done:\n\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"curl -X POST \\\\\\n-H \\\"X-API-KEY: API_KEY\\\" \\\\\\n-H \\\"Content-type: application/json\\\" \\\\\\n-d '{\\\"books\\\": [1,2,3,5]} \\\\\\n\\\"https://api.syncano.io/v1.1/instances/INSTANCE_NAME/classes/authors/objects/\\\"\",\n      \"language\": \"curl\"\n    },\n    {\n      \"code\": \"import syncano\\nfrom syncano.models import Object\\n\\nconnection = syncano.connect(api_key='API_KEY')\\n\\nObject.please.create(\\n  instance_name=\\\"INSTANCE_NAME\\\",\\n  class_name=\\\"authors\\\",\\n  books=[1,2,3,4]\\n)\",\n      \"language\": \"python\"\n    },\n    {\n      \"code\": \"var Syncano = require(\\\"syncano\\\");  // CommonJS\\nvar connection = Syncano({accountKey: \\\"ACCOUNT_KEY\\\"});\\nvar DataObject = connection.DataObject;\\n\\nvar author = {\\n  books: [1,2,3,4],\\n  instanceName: \\\"INSTANCE_NAME\\\",\\n  className: \\\"class_with_relations\\\"\\n};\\n\\nDataObject.please().create(author).then(function(author) {\\n  console.log(\\\"author: \\\", author);\\n});\",\n      \"language\": \"javascript\"\n    },\n    {\n      \"code\": \"// not supported\",\n      \"language\": \"java\",\n      \"name\": \"Android\"\n    },\n    {\n      \"code\": \"//define Class of an object\\n@interface Authors : SCDataObject\\n@property (nonatomic,copy) SCRelation *books;\\n@end\\n  \\n@implementation Authors\\n@end\\n  \\n//creating a Data Object with reference using Reference class\\nAuthors *authors = [Authors new];\\nauthors.books = [SCRelation relationWithTargetClass:[Book class]];\\n[[Book please] giveMeDataObjectsWithCompletion:^(NSArray * _Nullable books, NSError * _Nullable error) {\\n    //handle error            \\n\\t[authors addMembers:books forRelationWithKey:@\\\"books\\\" withCompletion:^(NSError * _Nullable error) {\\n     //handle error            \\n\\t}];\\n}];\",\n      \"language\": \"objectivec\"\n    },\n    {\n      \"code\": \"//define Class of an object\\nclass Authors : SCDataObject {\\n    var books:SCRelation?\\n}\\n\\n//creating a Data Object using Reference class\\nlet authors:Authors = Authors()\\nauthors.books = SCRelation(targetClass: Book.self)\\nBook.please().giveMeDataObjects { (books, error) in\\n    //handle error\\n    authors.addMembers(books as! [Book], forRelationWithKey: \\\"books\\\", withCompletion: { (error) in\\n        //handle error\\n    })\\n}\",\n      \"language\": \"swift\"\n    },\n    {\n      \"code\": \"require 'syncano'\\n\\nauthors = instance.classes.find('authors')\\n\\nauthors.objects.create(relation: [1,2,3,4])\",\n      \"language\": \"ruby\"\n    },\n    {\n      \"code\": \"// NOT AVAILABLE\",\n      \"language\": \"csharp\",\n      \"name\": \"Unity\"\n    }\n  ]\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Filtering on Relation fields\"\n}\n[/block]\n\n[block:callout]\n{\n  \"type\": \"info\",\n  \"title\": \"Previous reading\",\n  \"body\": \"This section talks about making queries on Relation fields. In order to fully understand it you should be familiar with the following chapters:\\n- [Data Classes](doc:classes-overview) (info on adding index fields)\\n- [Data Objects Filtering & Ordering](doc:data-objects-filtering-ordering)\"\n}\n[/block]\nProvided that you have a `filter_index` set to true on relation field in your Data Class schema, you can do two kinds of queries on it:\n- filter by `_contains`\n- filter by `_is`\n\n### Filtering by `_contains`\n\nIt's a simple query that allows for checking whether a relation array contains the Data Object IDs that we are looking for. An example call with a `_contains` query will look like this:\n\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"curl -X GET -G \\\\\\n-H \\\"X-API-KEY: API_KEY\\\" \\\\\\n-d 'query={\\\"books\\\":{\\\"_contains\\\":[1,2,4,5]}}' \\\\\\n\\\"https://api.syncano.io/v1.1/instances/INSTANCE_NAME/classes/authors/objects/\\\"\\n\",\n      \"language\": \"curl\"\n    },\n    {\n      \"code\": \"var Syncano = require(\\\"syncano\\\");  // CommonJS\\nvar connection = Syncano({accountKey: \\\"ACCOUNT_KEY\\\"});\\nvar DataObject = connection.DataObject;\\n\\nvar list = {instanceName: \\\"INSTANCE_NAME\\\", className: \\\"authors\\\"};\\n\\nDataObject.please()\\n\\t.list(list)\\n\\t.contains('books', [1,2,3,4,5])\\n\\t.then(callback);\",\n      \"language\": \"javascript\"\n    },\n    {\n      \"code\": \"import syncano\\nfrom syncano.models import Object\\n\\nsyncano.connect(api_key=\\\"API_KEY\\\")\\n\\nrelations = [1,3,4,5]\\nObject.please.list(\\n    instance_name=\\\"INSTANCE_NAME\\\",\\n    class_name=\\\"authors\\\"\\n).filter(books__contains=relations)\",\n      \"language\": \"python\"\n    },\n    {\n      \"code\": \"// not supported\",\n      \"language\": \"java\",\n      \"name\": \"Android\"\n    },\n    {\n      \"code\": \"SCPredicate *bookPredicate = [SCPredicate whereKey:@\\\"authors\\\" contains:@[1,2,3,4]];\\n[[Book please] giveMeDataObjectsWithPredicate:bookPredicate parameters:nil completion:^(NSArray *books, NSError *error) {\\n        //error handling\\n}];\",\n      \"language\": \"objectivec\",\n      \"name\": \"Objective-C\"\n    },\n    {\n      \"code\": \"let bookPredicate = SCPredicate.whereKey(\\\"authors\\\", contains: [1,2,3,4])\\nBook.please().giveMeDataObjectsWithPredicate(bookPredicate, parameters: nil) { books, error in\\n    //error handling\\n}\",\n      \"language\": \"objectivec\",\n      \"name\": \"Swift\"\n    },\n    {\n      \"code\": \"// NOT AVAILABLE\",\n      \"language\": \"csharp\",\n      \"name\": \"Unity\"\n    }\n  ]\n}\n[/block]\n\n### Filtering by `_is`\n\nFiltering by `_is` option will allow to filter all the results by a certain property that a related Data Object might have. If you decided that you'd like to know whether books related to authors contained the word \"potato\" in their titles, you could find out by making this query:\n\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"curl -X GET -G \\\\\\n-H \\\"X-API-KEY: API_KEY\\\" \\\\\\n-d 'query={\\\"books\\\":{\\\"_is\\\":{\\\"title\\\":{\\\"_contains\\\":\\\"potato\\\"}}}}' \\\\\\n\\\"https://api.syncano.io/v1.1/instances/INSTANCE_NAME/classes/authors/objects/\\\"\\n\",\n      \"language\": \"curl\"\n    },\n    {\n      \"code\": \"var Syncano = require(\\\"syncano\\\");  // CommonJS\\nvar connection = Syncano({accountKey: \\\"ACCOUNT_KEY\\\"});\\nvar DataObject = connection.DataObject;\\n\\nvar list = {instanceName: \\\"INSTANCE_NAME\\\", className: \\\"authors\\\"};\\nvar filter = {\\\"title\\\":{\\\"_contains\\\":\\\"potato\\\"}};\\n\\nDataObject.please()\\n  .list(list)\\n\\t.is('books', filter)\\n\\t.then(callback);\",\n      \"language\": \"javascript\"\n    },\n    {\n      \"code\": \"import syncano\\nfrom syncano.models import Object\\n\\nsyncano.connect(api_key=\\\"API_KEY\\\")\\n\\nObject.please.list(\\n    instance_name=\\\"INSTANCE_NAME\\\",\\n    class_name=\\\"authors\\\"\\n).filter(books__title__contains=\\\"potato\\\")\",\n      \"language\": \"python\"\n    },\n    {\n      \"code\": \"ResponseGetList<Book> response = Syncano.please(Book.class).where().in(\\\"author\\\", new Integer[] {1, 2, 3, 4}).get();\",\n      \"language\": \"java\",\n      \"name\": \"Android\"\n    },\n    {\n      \"code\": \"SCPredicate *numOfPagespredicate = [SCPredicate whereKey:@\\\"numOfPages\\\" isGreaterThanNumber:@123];\\nSCPredicate *predicate = [SCPredicate whereRelationWithKey:@\\\"books\\\" satisfiesPredicate:numOfPagespredicate];\\n[[Authors please] giveMeDataObjectsWithPredicate:predicate parameters:nil completion:^(NSArray * _Nullable objects, NSError * _Nullable error) {\\n    \\n}];\",\n      \"language\": \"objectivec\",\n      \"name\": \"Objective-C\"\n    },\n    {\n      \"code\": \"let numOfPagesPredicate = SCPredicate.whereKey(\\\"numOfPages\\\", isGreaterThanNumber: 123)\\nlet predicate = SCPredicate.whereKey(\\\"books\\\", satisfiesPredicate: numOfPagesPredicate)\\nAuthors.please().giveMeDataObjects(withPredicate: predicate, parameters: nil) { (authors, error) in\\n    //handle error\\n}\",\n      \"language\": \"objectivec\",\n      \"name\": \"Swift\"\n    },\n    {\n      \"code\": \"// NOT AVAILABLE\",\n      \"language\": \"csharp\",\n      \"name\": \"Unity\"\n    }\n  ]\n}\n[/block]\n\n[block:callout]\n{\n  \"type\": \"info\",\n  \"body\": \"Since filtering by `_is` is a nested query, you'll need to set up indexing on the schema field you are relating to. In the example above, the `title` field from books data class should have `filter_index` set to true. Otherwise we won't be able to filter on it.\"\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Summary\"\n}\n[/block]\nTo sum up:\n- You can use `reference` field to create one-to-one relationships between Data Objects\n- You can use `relations` field to create one-to-many and many-to-many relationships between Data Objects","excerpt":"In this chapter you will learn how to use Relations and References between Data Objects","slug":"relations","type":"basic","title":"Relations & References"}

Relations & References

In this chapter you will learn how to use Relations and References between Data Objects

## Chapter contents 1. [Overview](#overview) 2. [one-to-one relation](#one-to-one-relation) 3. [one-to-many & many-to-many relations](#one-to-many--many-to-many-relations) 4. [Filtering on Relation and Reference fields](#filtering-on-relation-and-reference-fields) 5. [Summary](#summary) [block:api-header] { "type": "basic", "title": "Overview" } [/block] In Syncano, you can create links between Data Objects called relationships. There are 3 possible options here: - `one-to-one` - One Data Object is connected to another. - `one-to-many` - One Data Object has relations with many other. - `many-to-many` - This type of relation allows for creating a net of connections. We will dig into those solutions in the sections below. [block:api-header] { "type": "basic", "title": "one-to-one relation" } [/block] one-to-one relationships can come in handy in a situation where one Data Object will need to be split into two. This shouldn't be very common but there are couple of use cases: - Limiting access to part of the stored data - In this case Data Objects could be in different Data Classes, where different users would have access to each of these Data Classes. This would allow making only part of the data visible based on permissions. - Splitting Data Object because of size limits - Data Object size limit is 32 kB. In case this is not enough you could store rest of the data in a referenced Data Object. In most of cases using a `file` schema field type and storing data there would be a better solution but using a reference will work too. ### Creating one-to-one reference To create a reference you'll need to create a Data Class with a `reference` schema field type (you can read about Data Classes and their schemas [here](doc:classes-overview)). It's a bit different from other schema field types because it has and additional property called `Target Data Class`. In this dropdown you can choose whether referenced Data Objects will be in the same (`self` option) or a different Data Class. [block:image] { "images": [ { "image": [ "https://files.readme.io/99d8xDsSImYTbXTHlDQt_class_ref.png", "class_ref.png", "1438", "751", "#3476b5", "" ] } ] } [/block] Once you have this set up you can create Data Objects with references. Reference value is the id of a Data Object that will be linked: [block:code] { "codes": [ { "code": "curl -X POST \\\n-H \"X-API-KEY: API_KEY\" \\\n-H \"Content-type: application/json\" \\\n-d '{\"reference\": 1}' \\\n\"https://api.syncano.io/v1.1/instances/INSTANCE_NAME/classes/data_class_with_references/objects/\"", "language": "curl" }, { "code": "import syncano\nfrom syncano.models import Object\n\nconnection = syncano.connect(api_key='API_KEY')\n\nObject.please.create(\n instance_name=\"INSTANCE_NAME\",\n class_name=\"class_with_references\",\n reference=1\n)", "language": "python" }, { "code": "var Syncano = require(\"syncano\"); // CommonJS\nvar connection = Syncano({accountKey: \"ACCOUNT_KEY\"});\nvar DataObject = connection.DataObject;\n\nvar ref = {\n reference: 1,\n instanceName: \"INSTANCE_NAME\",\n className: \"class_with_references\"\n};\n\nDataObject.please().create(ref).then(function(ref) {\n console.log(\"reference\", ref);\n});", "language": "javascript" }, { "code": "ReferenceClass ref = new ReferenceClass();\nref.setId(1);\n\nClassWithReference objectWithRef = new ClassWithReference();\nobjectWithRef.reference = ref;\n\nResponse<ClassWithReference> response = objectWithRef.save();", "language": "java", "name": "Android" }, { "code": "@interface Author : SCDataObject\n@property (nonatomic,retain) NSString *firstName;\n@property (nonatomic,retain) NSString *secondName;\n@end\n\n@interface Book : SCDataObject\n@property (nonatomic,retain) NSString *title;\n@property (nonatomic,retain) NSNumber *numOfPages;\n@property (nonatomic,retain) Author *author;\n@end\n\n \n//creating a Data Object with reference using Reference class\nAuthor *author = [Author new];\nauthor.firstName = @\"AUTHOR-FIRST-NAME\";\nauthor.secondName = @\"AUTHOR-SECOND-NAME\";\n[author saveWithCompletionBlock:^(NSError * _Nullable error) {\n if (error == nil) {\n Book *book = [Book new];\n book.author = author\n [book saveWithCompletionBlock:^(NSError * _Nullable error) {\n //handle error\n }]\n }\n}];", "language": "objectivec" }, { "code": "class Author: SCDataObject {\n var firstName = \"\"\n var secondName = \"\"\n \n}\n\nclass Book: SCDataObject {\n var title = \"\"\n var numberOfPages = 0\n var author:Author?\n}\n\n//creating a Data Object with reference using Reference class\nlet author:Author = Author()\nauthor.firstName = \"AUTHOR-FIRST-NAME\"\nauthor.secondName = \"AUTHOR-SECOND-NAME\"\nauthor.saveWithCompletionBlock { (error) in\n if error == nil {\n let book = Book()\n book.author = author\n book.saveWithCompletionBlock({ (error) in\n //handle error\n })\n }\n}", "language": "swift" }, { "code": "require 'syncano'\n\nclass_with_reference = instance.classes.find('class_with_reference')\n\nclass_with_reference.objects.create(reference: 1)", "language": "ruby" }, { "code": "// NOT AVAILABLE", "language": "csharp", "name": "Unity" } ] } [/block] [block:api-header] { "type": "basic", "title": "one-to-many & many-to-many relations" } [/block] To create `one-to-many` or `many-to-many` relationships you can use Syncano's `relation` field. It's an array where you can store ids of a connected Data Object. So, for example if you had an `Authors` and `Books` data classes you could create a relation field in the `Authors` Data Class. This field could hold an array of Data Object ids representing books from `Books` data class. [block:image] { "images": [ { "image": [ "https://files.readme.io/gXYHforbTICxeRuw8e9q_class_relation.png", "class_relation.png", "2548", "1310", "#3a79af", "" ] } ] } [/block] ### Creating one-to-many and many-to-many relation Once you have a proper set up, you can start making Data Objects with relations. This is how it could be done: [block:code] { "codes": [ { "code": "curl -X POST \\\n-H \"X-API-KEY: API_KEY\" \\\n-H \"Content-type: application/json\" \\\n-d '{\"books\": [1,2,3,5]} \\\n\"https://api.syncano.io/v1.1/instances/INSTANCE_NAME/classes/authors/objects/\"", "language": "curl" }, { "code": "import syncano\nfrom syncano.models import Object\n\nconnection = syncano.connect(api_key='API_KEY')\n\nObject.please.create(\n instance_name=\"INSTANCE_NAME\",\n class_name=\"authors\",\n books=[1,2,3,4]\n)", "language": "python" }, { "code": "var Syncano = require(\"syncano\"); // CommonJS\nvar connection = Syncano({accountKey: \"ACCOUNT_KEY\"});\nvar DataObject = connection.DataObject;\n\nvar author = {\n books: [1,2,3,4],\n instanceName: \"INSTANCE_NAME\",\n className: \"class_with_relations\"\n};\n\nDataObject.please().create(author).then(function(author) {\n console.log(\"author: \", author);\n});", "language": "javascript" }, { "code": "// not supported", "language": "java", "name": "Android" }, { "code": "//define Class of an object\n@interface Authors : SCDataObject\n@property (nonatomic,copy) SCRelation *books;\n@end\n \n@implementation Authors\n@end\n \n//creating a Data Object with reference using Reference class\nAuthors *authors = [Authors new];\nauthors.books = [SCRelation relationWithTargetClass:[Book class]];\n[[Book please] giveMeDataObjectsWithCompletion:^(NSArray * _Nullable books, NSError * _Nullable error) {\n //handle error \n\t[authors addMembers:books forRelationWithKey:@\"books\" withCompletion:^(NSError * _Nullable error) {\n //handle error \n\t}];\n}];", "language": "objectivec" }, { "code": "//define Class of an object\nclass Authors : SCDataObject {\n var books:SCRelation?\n}\n\n//creating a Data Object using Reference class\nlet authors:Authors = Authors()\nauthors.books = SCRelation(targetClass: Book.self)\nBook.please().giveMeDataObjects { (books, error) in\n //handle error\n authors.addMembers(books as! [Book], forRelationWithKey: \"books\", withCompletion: { (error) in\n //handle error\n })\n}", "language": "swift" }, { "code": "require 'syncano'\n\nauthors = instance.classes.find('authors')\n\nauthors.objects.create(relation: [1,2,3,4])", "language": "ruby" }, { "code": "// NOT AVAILABLE", "language": "csharp", "name": "Unity" } ] } [/block] [block:api-header] { "type": "basic", "title": "Filtering on Relation fields" } [/block] [block:callout] { "type": "info", "title": "Previous reading", "body": "This section talks about making queries on Relation fields. In order to fully understand it you should be familiar with the following chapters:\n- [Data Classes](doc:classes-overview) (info on adding index fields)\n- [Data Objects Filtering & Ordering](doc:data-objects-filtering-ordering)" } [/block] Provided that you have a `filter_index` set to true on relation field in your Data Class schema, you can do two kinds of queries on it: - filter by `_contains` - filter by `_is` ### Filtering by `_contains` It's a simple query that allows for checking whether a relation array contains the Data Object IDs that we are looking for. An example call with a `_contains` query will look like this: [block:code] { "codes": [ { "code": "curl -X GET -G \\\n-H \"X-API-KEY: API_KEY\" \\\n-d 'query={\"books\":{\"_contains\":[1,2,4,5]}}' \\\n\"https://api.syncano.io/v1.1/instances/INSTANCE_NAME/classes/authors/objects/\"\n", "language": "curl" }, { "code": "var Syncano = require(\"syncano\"); // CommonJS\nvar connection = Syncano({accountKey: \"ACCOUNT_KEY\"});\nvar DataObject = connection.DataObject;\n\nvar list = {instanceName: \"INSTANCE_NAME\", className: \"authors\"};\n\nDataObject.please()\n\t.list(list)\n\t.contains('books', [1,2,3,4,5])\n\t.then(callback);", "language": "javascript" }, { "code": "import syncano\nfrom syncano.models import Object\n\nsyncano.connect(api_key=\"API_KEY\")\n\nrelations = [1,3,4,5]\nObject.please.list(\n instance_name=\"INSTANCE_NAME\",\n class_name=\"authors\"\n).filter(books__contains=relations)", "language": "python" }, { "code": "// not supported", "language": "java", "name": "Android" }, { "code": "SCPredicate *bookPredicate = [SCPredicate whereKey:@\"authors\" contains:@[1,2,3,4]];\n[[Book please] giveMeDataObjectsWithPredicate:bookPredicate parameters:nil completion:^(NSArray *books, NSError *error) {\n //error handling\n}];", "language": "objectivec", "name": "Objective-C" }, { "code": "let bookPredicate = SCPredicate.whereKey(\"authors\", contains: [1,2,3,4])\nBook.please().giveMeDataObjectsWithPredicate(bookPredicate, parameters: nil) { books, error in\n //error handling\n}", "language": "objectivec", "name": "Swift" }, { "code": "// NOT AVAILABLE", "language": "csharp", "name": "Unity" } ] } [/block] ### Filtering by `_is` Filtering by `_is` option will allow to filter all the results by a certain property that a related Data Object might have. If you decided that you'd like to know whether books related to authors contained the word "potato" in their titles, you could find out by making this query: [block:code] { "codes": [ { "code": "curl -X GET -G \\\n-H \"X-API-KEY: API_KEY\" \\\n-d 'query={\"books\":{\"_is\":{\"title\":{\"_contains\":\"potato\"}}}}' \\\n\"https://api.syncano.io/v1.1/instances/INSTANCE_NAME/classes/authors/objects/\"\n", "language": "curl" }, { "code": "var Syncano = require(\"syncano\"); // CommonJS\nvar connection = Syncano({accountKey: \"ACCOUNT_KEY\"});\nvar DataObject = connection.DataObject;\n\nvar list = {instanceName: \"INSTANCE_NAME\", className: \"authors\"};\nvar filter = {\"title\":{\"_contains\":\"potato\"}};\n\nDataObject.please()\n .list(list)\n\t.is('books', filter)\n\t.then(callback);", "language": "javascript" }, { "code": "import syncano\nfrom syncano.models import Object\n\nsyncano.connect(api_key=\"API_KEY\")\n\nObject.please.list(\n instance_name=\"INSTANCE_NAME\",\n class_name=\"authors\"\n).filter(books__title__contains=\"potato\")", "language": "python" }, { "code": "ResponseGetList<Book> response = Syncano.please(Book.class).where().in(\"author\", new Integer[] {1, 2, 3, 4}).get();", "language": "java", "name": "Android" }, { "code": "SCPredicate *numOfPagespredicate = [SCPredicate whereKey:@\"numOfPages\" isGreaterThanNumber:@123];\nSCPredicate *predicate = [SCPredicate whereRelationWithKey:@\"books\" satisfiesPredicate:numOfPagespredicate];\n[[Authors please] giveMeDataObjectsWithPredicate:predicate parameters:nil completion:^(NSArray * _Nullable objects, NSError * _Nullable error) {\n \n}];", "language": "objectivec", "name": "Objective-C" }, { "code": "let numOfPagesPredicate = SCPredicate.whereKey(\"numOfPages\", isGreaterThanNumber: 123)\nlet predicate = SCPredicate.whereKey(\"books\", satisfiesPredicate: numOfPagesPredicate)\nAuthors.please().giveMeDataObjects(withPredicate: predicate, parameters: nil) { (authors, error) in\n //handle error\n}", "language": "objectivec", "name": "Swift" }, { "code": "// NOT AVAILABLE", "language": "csharp", "name": "Unity" } ] } [/block] [block:callout] { "type": "info", "body": "Since filtering by `_is` is a nested query, you'll need to set up indexing on the schema field you are relating to. In the example above, the `title` field from books data class should have `filter_index` set to true. Otherwise we won't be able to filter on it." } [/block] [block:api-header] { "type": "basic", "title": "Summary" } [/block] To sum up: - You can use `reference` field to create one-to-one relationships between Data Objects - You can use `relations` field to create one-to-many and many-to-many relationships between Data Objects