---
title: 1:N Relationship
slug: docs-kr/react-native/parse-sdk/data-objects/one-to-many-relationship
description: React Native에서 Parse를 활용해 1:N 데이터 객체 관계를 효율적으로 생성하고 쿼리하는 방법에 대해 알아보세요.
image: https://www.back4app.com/images/logo-social.png
createdAt: 2024-03-19T11:42:09.703Z
---

# 일대다 관계

## 소개

많은 백엔드의 핵심에는 데이터를 저장할 수 있는 기능이 있습니다. Parse를 사용하면 데이터 객체를 저장하고 이들 간의 관계를 설정할 수 있습니다. 데이터 관계는 각 데이터 객체가 다른 객체와 어떻게 관련되거나 연관되는지를 표준화합니다. 이는 복잡한 쿼리를 구축하고 실행할 때 추가적인 힘을 줄 수 있습니다. 주요 관계 유형은 세 가지입니다:

- <font color="#2166ae">`일대다`</font>, 하나의 객체가 여러 다른 객체와 관련될 수 있는 경우;
- <font color="#2166ae">`일대일`</font>, 두 객체 간의 직접적인 관계를 설정하는 경우;
- <font color="#2166ae">`다대다`</font>, 여러 객체 간에 복잡한 관계를 생성할 수 있는 경우.

이 가이드에서는 가장 일반적인 관계인 일대다에 초점을 맞출 것입니다. 데이터 저장 백엔드는 일반적으로 이러한 연관에 대한 명시적인 선언을 요구하며, 심지어는 스스로 관계형 테이블을 생성하여 이들의 조인을 관리해야 할 수도 있습니다. Parse는 이를 자동으로 처리하여 데이터 관계를 구축하는 동안 오류의 가능성을 제거하고 애플리케이션 모델링 프로세스를 가속화합니다.

Parse에서 일대다 관계를 생성하는 두 가지 방법이 있습니다. 첫 번째는 <font color="#2166ae">`Parse.Object`</font> 포인터를 사용하는 것으로, 생성 및 쿼리 시간에서 가장 빠릅니다. 두 번째는 <font color="#2166ae">`배열`</font>을 사용하는 것으로, 크기에 따라 쿼리 시간이 느려질 수 있습니다. 이러한 성능 문제로 인해, 이제부터는 포인터 예제만 사용할 것입니다.

이 가이드에서는 세 가지 주요 데이터 연관을 포함하는 React Native 도서 등록 애플리케이션을 구현할 것입니다. Back4App과 React Native를 사용하여 일대다 데이터 관계를 생성하고 쿼리하는 방법을 배울 것입니다.

::embed[]{url="https://www.youtube.com/embed/MUebHAqJXdA"}

:::hint{type="success"}
**언제든지 이 프로젝트에 대한 접근은 우리의 GitHub 리포지토리를 통해 스타일과 완전한 코드를 확인할 수 있습니다.**

- [JavaScript 예제 리포지토리](https://github.com/templates-back4app/react-native-js-associations)
- [TypeScript 예제 리포지토리](https://github.com/templates-back4app/react-native-ts-associations)
:::

## 전제 조건

:::hint{type="info"}
**이 튜토리얼을 완료하려면 다음이 필요합니다:**

- Back4App에 연결된 React Native 앱을 생성해야 합니다 [Back4App](https://www.back4app.com/docs/react-native/parse-sdk/react-native-sdk).
- 이 가이드에서 제공하는 화면 레이아웃을 테스트/사용하려면<font color="#2166ae">`react-native-paper`</font>[라이브러리](https://github.com/callstack/react-native-paper)를 설정해야 합니다.
:::

## 목표

Parse의 일대다 관계를 사용하여 도서관 React Native 앱을 모델링합니다.

## 1 - 책 클래스 이해하기

이 가이드에서는 책 등록 애플리케이션 예제를 사용할 것이므로, 먼저 이 데이터베이스에서 객체 관계가 어떻게 구성되어 있는지 이해해야 합니다. 사용하게 될 주요 객체 클래스는 <font color="#2166ae">`Book`</font> 클래스이며, 등록된 각 책 항목을 저장합니다. 또한, 다음은 다른 네 개의 객체 클래스입니다:

- <font color="#2166ae">`출판사`</font>: 책 출판사 이름, <font color="#2166ae">`Book`</font>, 일대다 관계
- <font color="#2166ae">`장르`</font>: 책 장르, <font color="#2166ae">`Book`</font>, 일대다 관계. 이 예제에서는 책이 하나의 장르만 가질 수 있다고 가정합니다;
- <font color="#2166ae">`저자`</font>: 책 저자, <font color="#2166ae">`Book`</font>, 다대다 관계, 책은 여러 저자를 가질 수 있고 저자도 여러 책을 가질 수 있습니다;
- <font color="#2166ae">`ISDB`</font>: 책 ISDB 식별 번호, <font color="#2166ae">`Book`</font>, 일대일 관계, 이 번호는 각 책마다 고유합니다.

다음은 이러한 데이터베이스 테이블의 시각적 표현입니다:

![](https://api.archbee.com/api/optimize/yD3zCY-NNBBIfd0uqcfR5/wfFSmbYqKoR49nmlOkZ2__image.png)

간단히 하기 위해, 각 객체 클래스가 문자열 유형의 <font color="#2166ae">`이름`</font> 속성(<font color="#2166ae">`제목`</font>)을 가지고 있다고 가정하겠습니다. <font color="#2166ae">`책`</font>과 같은 추가적인 관계 속성은 제외합니다.

## 2 - 일대다 관계 생성

이 단계로 들어가기 전에 React Native Library 앱 예제를 복제하고 실행할 것을 권장합니다 ([JavaScript 예제 저장소](https://github.com/templates-back4app/react-native-js-associations), [TypeScript 예제 저장소](https://github.com/templates-back4app/react-native-ts-associations)). 이 애플리케이션은 등록된 책을 나열하는 화면과 새로운 책을 생성하는 화면의 두 가지 주요 화면을 가지고 있습니다. 책 등록 양식에는 다른 관련 객체에 대한 직접 링크가 있어 사용자가 출판사나 장르 옵션을 선택하면 양식 필드가 전체 <font color="#2166ae">`Parse.Object`</font> 인스턴스를 보유하게 됩니다.

::Image[]{src="https://api.archbee.com/api/optimize/yD3zCY-NNBBIfd0uqcfR5/HFle1L6_yx8-Vg1IAQ20I_image.png" size="50" width="346" height="730" position="center" showCaption="false"}

이 양식을 제출할 때 호출되는 책 생성 방법을 살펴보겠습니다:

:::CodeblockTabs
JavaScript

```javascript
1	const createBook = async function () {
2	  try {
3	    // These values come from state variables linked to
4	    // the screen form fields, retrieving the user choices
5	    // as a complete Parse.Object, when applicable;
6	    const bookTitleValue = bookTitle;
7	    const bookISBDValue = bookISBD;
8	    // For example, bookPublisher holds the value from
9	    // RadioButton.Group field with its options being every
10	    // Publisher parse object instance saved on server, which is
11	    // queried on screen load via useEffect
12	    const bookPublisherObject = bookPublisher;
13	    const bookGenreObject = bookGenre;
14	    // bookAuthors can be an array of Parse.Objects, since the book
15	    // may have more than one Author
16	    const bookAuthorsObjects = bookAuthors;
17	
18	    // Creates a new parse object instance
19	    let Book = new Parse.Object('Book');
20	
21	    // Set data to parse object
22	    // Simple title field
23	    Book.set('title', bookTitleValue);
24	
25	    // 1:1 relation, need to check for uniqueness of value before creating a new ISBD object
26	    let isbdQuery = new Parse.Query('ISBD');
27	    isbdQuery.equalTo('name', bookISBDValue);
28	    let isbdQueryResult = await isbdQuery.first();
29	    if (isbdQueryResult !== null && isbdQueryResult !== undefined) {
30	      // If first returns a valid object instance, it means that there
31	      // is at least one instance of ISBD with the informed value
32	      Alert.alert(
33	        'Error!',
34	        'There is already an ISBD instance with this value!',
35	      );
36	      return false;
37	    } else {
38	      // Create a new ISBD object instance to create a one-to-one relation on saving
39	      let ISBD = new Parse.Object('ISBD');
40	      ISBD.set('name', bookISBDValue);
41	      ISBD = await ISBD.save();
42	      // Set the new object to the new book object ISBD field
43	      Book.set('isbd', ISBD);
44	    }
45	
46	    // One-to-many relations can be set in two ways:
47	    // add direct object to field (Parse will convert to pointer on save)
48	    Book.set('publisher', bookPublisherObject);
49	    // or add pointer to field
50	    Book.set('genre', bookGenreObject.toPointer());
51	
52	    // many-to-many relation
53	    // Create a new relation so data can be added
54	    let authorsRelation = Book.relation('authors');
55	    // bookAuthorsObjects is an array of Parse.Objects,
56	    // you can add to relation by adding the whole array or object by object
57	    authorsRelation.add(bookAuthorsObjects);
58	
59	    // After setting the values, save it on the server
60	    try {
61	      await Book.save();
62	      // Success
63	      Alert.alert('Success!');
64	      navigation.goBack();
65	      return true;
66	    } catch (error) {
67	      // Error can be caused by lack of Internet connection
68	      Alert.alert('Error!', error.message);
69	      return false;
70	    }
71	  } catch (error) {
72	    // Error can be caused by lack of value selection
73	    Alert.alert(
74	      'Error!',
75	      'Make sure to select valid choices in Publisher, Genre and Author fields!',
76	    );
77	    return false;
78	  }
79	};
```

```typescript
1	const createBook = async function (): Promise<boolean> {
2	  try {
3	    // These values come from state variables linked to
4	    // the screen form fields, retrieving the user choices
5	    // as a complete Parse.Object, when applicable;
6	    const bookTitleValue: string = bookTitle;
7	    const bookISBDValue: string = bookISBD;
8	    // For example, bookPublisher holds the value from
9	    // RadioButton.Group field with its options being every
10	    // Publisher parse object instance saved on server, which is
11	    // queried on screen load via useEffect
12	    const bookPublisherObject: Parse.Object = bookPublisher;
13	    const bookGenreObject: Parse.Object = bookGenre;
14	    // bookAuthors can be an array of Parse.Objects, since the book
15	    // may have more than one Author
16	    const bookAuthorsObjects: [Parse.Object] = bookAuthors;
17	
18	    // Creates a new parse object instance
19	    let Book: Parse.Object = new Parse.Object('Book');
20	
21	    // Set data to parse object
22	    // Simple title field
23	    Book.set('title', bookTitleValue);
24	
25	    // 1:1 relation, need to check for uniqueness of value before creating a new ISBD object
26	    let isbdQuery: Parse.Query = new Parse.Query('ISBD');
27	    isbdQuery.equalTo('name', bookISBDValue);
28	    let isbdQueryResult: Parse.Object = await isbdQuery.first();
29	    if (isbdQueryResult !== null && isbdQueryResult !== undefined) {
30	      // If first returns a valid object instance, it means that there
31	      // is at least one instance of ISBD with the informed value
32	      Alert.alert(
33	        'Error!',
34	        'There is already an ISBD instance with this value!',
35	      );
36	      return false;
37	    } else {
38	      // Create a new ISBD object instance to create a one-to-one relation on saving
39	      let ISBD: Parse.Object = new Parse.Object('ISBD');
40	      ISBD.set('name', bookISBDValue);
41	      ISBD = await ISBD.save();
42	      // Set the new object to the new book object ISBD field
43	      Book.set('isbd', ISBD);
44	    }
45	
46	    // One-to-many relations can be set in two ways:
47	    // add direct object to field (Parse will convert to pointer on save)
48	    Book.set('publisher', bookPublisherObject);
49	    // or add pointer to field
50	    Book.set('genre', bookGenreObject.toPointer());
51	
52	    // many-to-many relation
53	    // Create a new relation so data can be added
54	    let authorsRelation = Book.relation('authors');
55	    // bookAuthorsObjects is an array of Parse.Objects,
56	    // you can add to relation by adding the whole array or object by object
57	    authorsRelation.add(bookAuthorsObjects);
58	
59	    // After setting the values, save it on the server
60	    try {
61	      await Book.save();
62	      // Success
63	      Alert.alert('Success!');
64	      navigation.goBack();
65	      return true;
66	    } catch (error) {
67	      // Error can be caused by lack of Internet connection
68	      Alert.alert('Error!', error.message);
69	      return false;
70	    }
71	  } catch (error) {
72	    // Error can be caused by lack of value selection
73	    Alert.alert(
74	      'Error!',
75	      'Make sure to select valid choices in Publisher, Genre and Author fields!',
76	    );
77	    return false;
78	  }
79	};
```
:::

새 책 <font color="#2166ae">`bookPublisherObject`</font>와 <font color="#2166ae">`bookGenreObject`</font>이 어떻게 설정되는지 보세요. <font color="#2166ae">`Parse.Object`</font> 인스턴스에 대해. Parse에서 일대다 관계를 만드는 것이 얼마나 간단한지 보세요: 대상 객체 인스턴스를 할당하거나 <font color="#2166ae">`Parse.Object.set`</font> 메서드를 사용하여 포인터를 사용할 수 있습니다. 이 메서드는 두 개의 인수를 받습니다: 필드 이름과 설정할 값. Parse는 포인터 데이터 유형 열을 생성하고 대시보드에서 빠른 액세스를 위한 직접 링크를 생성합니다.

![](https://api.archbee.com/api/optimize/yD3zCY-NNBBIfd0uqcfR5/VET2v9-ZUrlxO_yLPDU3a_image.png)

대시보드에서 객체 포인터 값을 클릭하면 참조된 객체 항목으로 이동합니다. 이는 무해한 기능처럼 보일 수 있지만, 수동으로 검색하는 것보다 디버깅 및 오류 추적을 훨씬 더 빠르게 만들어 줍니다.

## 3 - 일대다 관계 쿼리하기

일대다 관련 객체를 쿼리하는 것은 Parse에서 대부분 처리되기 때문에 매우 간단합니다. 책 등록 목록 화면의 쿼리 기능을 살펴보세요:

:::CodeblockTabs
JavaScript

```javascript
1	const queryBooks = async function () {
2	  // These values come from state variables linked to
3	  // the screen query RadioButton.Group fields, with its options being every
4	  // parse object instance saved on server from the referred class, which is
5	  // queried on screen load via useEffect; these variables retrievie the user choices
6	  // as a complete Parse.Object;
7	  const queryPublisherValue = queryPublisher;
8	  const queryGenreValue = queryGenre;
9	  const queryAuthorValue = queryAuthor;
10	  const queryIsbdValue = queryIsbd;
11	
12	  // Reading parse objects is done by using Parse.Query
13	  const parseQuery = new Parse.Query('Book');
14	
15	  // One-to-many queries
16	  if (queryPublisherValue !== '') {
17	    parseQuery.equalTo('publisher', queryPublisherValue);
18	  }
19	  if (queryGenreValue !== '') {
20	    parseQuery.equalTo('genre', queryGenreValue);
21	  }
22	
23	  // One-to-one query
24	  if (queryIsbdValue !== '') {
25	    parseQuery.equalTo('isbd', queryIsbdValue);
26	  }
27	
28	  // Many-to-many query
29	  // In this case, we need to retrieve books related to the chosen author
30	  if (queryAuthorValue !== '') {
31	    parseQuery.equalTo('authors', queryAuthorValue);
32	  }
33	
34	  try {
35	    let books = await parseQuery.find();
36	    // Many-to-many objects retrieval
37	    // In this example we need to get every related author Parse.Object
38	    // and add it to our query result objects
39	    for (let book of books) {
40	      // This query is done by creating a relation and querying it
41	      let bookAuthorsRelation = book.relation('authors');
42	      book.authorsObjects = await bookAuthorsRelation.query().find();
43	    }
44	    setQueriedBooks(books);
45	    return true;
46	  } catch (error) {
47	    // Error can be caused by lack of Internet connection
48	    Alert.alert('Error!', error.message);
49	    return false;
50	  }
51	};
```

```typescript
1	const queryBooks = async function (): Promise<boolean> {
2	  // These values come from state variables linked to
3	  // the screen query RadioButton.Group fields, with its options being every
4	  // parse object instance saved on server from the referred class, which is
5	  // queried on screen load via useEffect; these variables retrievie the user choices
6	  // as a complete Parse.Object;
7	  const queryPublisherValue: Parse.Object = queryPublisher;
8	  const queryGenreValue: Parse.Object = queryGenre;
9	  const queryAuthorValue: Parse.Object = queryAuthor;
10	  const queryIsbdValue: Parse.Object = queryIsbd;
11	
12	  // Reading parse objects is done by using Parse.Query
13	  const parseQuery: Parse.Query = new Parse.Query('Book');
14	
15	  // One-to-many queries
16	  if (queryPublisherValue !== '') {
17	    parseQuery.equalTo('publisher', queryPublisherValue);
18	  }
19	  if (queryGenreValue !== '') {
20	    parseQuery.equalTo('genre', queryGenreValue);
21	  }
22	
23	  // One-to-one query
24	  if (queryIsbdValue !== '') {
25	    parseQuery.equalTo('isbd', queryIsbdValue);
26	  }
27	
28	  // Many-to-many query
29	  // In this case, we need to retrieve books related to the chosen author
30	  if (queryAuthorValue !== '') {
31	    parseQuery.equalTo('authors', queryAuthorValue);
32	  }
33	
34	  try {
35	    let books: [Parse.Object] = await parseQuery.find();
36	    // Many-to-many objects retrieval
37	    // In this example we need to get every related author Parse.Object
38	    // and add it to our query result objects
39	    for (let book of books) {
40	      // This query is done by creating a relation and querying it
41	      let bookAuthorsRelation = book.relation('authors');
42	      book.authorsObjects = await bookAuthorsRelation.query().find();
43	    }
44	    setQueriedBooks(books);
45	    return true;
46	  } catch (error) {
47	    // Error can be caused by lack of Internet connection
48	    Alert.alert('Error!', error.message);
49	    return false;
50	  }
51	};
```
:::

이 경우, 특정 출판사나 장르와 관련된 책을 쿼리하려면 <font color="#2166ae">`Parse.Query.equalTo`</font> 메서드를 사용하여 <font color="#2166ae">`Parse.Object`</font> 인스턴스를 매개변수로 전달하면 됩니다. 쿼리 후, Parse는 결과 객체 내부에 모든 일대다 관계 필드의 완전한 인스턴스를 저장합니다. 이러한 객체 인스턴스에서 데이터를 검색하고 표시하려면 다음과 같이 <font color="#2166ae">`Parse.Object.get`</font> 메서드를 체인으로 연결할 수 있습니다: <font color="#2166ae">`bookParseObject.get(('publisher').get('name')`</font>. 다음은 이러한 getter를 사용하여 목록 항목에서 출판사 및 장르 이름을 검색하는 목록 화면의 모습입니다:

::Image[]{src="https://api.archbee.com/api/optimize/yD3zCY-NNBBIfd0uqcfR5/8ogG07fbntUTVQq5VT90E_image.png" size="50" width="352" height="733" position="center" showCaption="false"}

## 결론

이 가이드의 끝에서, React Native에서 Parse의 일대다 관계를 생성하고 쿼리하는 방법을 배웠습니다. 다음 가이드에서는 다대다 및 일대일 쿼리와 관계를 수행하는 방법을 보여드리겠습니다.
