웹 또는 모바일 클라이언트 라이브러리를 사용하여 Firestore 데이터베이스 만들기

이 빠른 시작에서는 Android, Apple 플랫폼, 웹, Unity 또는 C++ 클라이언트 라이브러리를 사용하여 Firestore를 설정하고, 데이터를 추가하고, 데이터를 읽는 방법을 설명합니다.

Firestore 데이터베이스 만들기

  1. Firebase 프로젝트를 아직 만들지 않았다면 Firebase Console에서 프로젝트 추가를 클릭한 후 화면의 안내에 따라 Firebase 프로젝트를 만들거나 기존 GCP 프로젝트에 Firebase 서비스를 추가합니다.

  2. Firebase Console의 탐색창에서 Firestore를 선택한 후 Firestore의 데이터베이스 만들기를 클릭합니다.

  3. Firestore 보안 규칙의 테스트 모드를 선택합니다.

    테스트 모드
    모바일 및 웹 클라이언트 라이브러리를 시작할 때 유용하지만 모든 사용자가 데이터를 읽고 덮어쓸 수 있습니다. 테스트 완료 후에 데이터 보안 섹션을 검토해야 합니다.
  4. 데이터베이스 위치를 선택합니다.

    • 이 위치 설정이 프로젝트의 기본 Google Cloud Platform(GCP) 리소스 위치입니다. 이 위치는 특히 기본 Cloud Storage 버킷 및 App Engine 앱(Cloud Scheduler 사용 시 필요)과 같이 위치 설정이 필요한 프로젝트의 GCP 서비스에 사용됩니다.

    • 위치를 선택할 수 없다면 프로젝트에 이미 기본 GCP 리소스 위치가 있는 것입니다. 이 위치는 프로젝트 생성 과정이나 위치 설정이 필요한 다른 서비스를 설정할 때 지정한 것입니다.

  5. 완료를 클릭합니다.

Firestore를 사용 설정하면 Cloud API Manager의 API도 사용 설정됩니다.

개발 환경 설정

필요한 종속 항목 및 클라이언트 라이브러리를 앱에 추가하세요.

웹 버전 9

  1. 안내에 따라 Firebase를 웹 앱에 추가합니다.
  2. Firebase와 Firestore를 모두 가져옵니다.
    import { initializeApp } from "firebase/app";
    import { getFirestore } from "firebase/firestore";
    

웹 버전 8

  1. 안내에 따라 Firebase를 웹 앱에 추가합니다.
  2. Firebase와 Firestore 라이브러리를 앱에 추가합니다.
    <script src="https://www.gstatic.com/firebasejs/8.10.1/firebase-app.js"></script>
    <script src="https://www.gstatic.com/firebasejs/8.10.1/firebase-firestore.js"></script>
    Firestore SDK는 npm 패키지로도 제공됩니다.
    npm install firebase@8.10.1 --save
    
    Firebase와 Firestore를 수동으로 요청해야 합니다.
    const firebase = require("firebase");
    // Required for side-effects
    require("firebase/firestore");
    
Apple 플랫폼

안내에 따라 Firebase를 Apple 앱에 추가합니다.

Swift Package Manager를 사용해 Firebase 종속 항목을 설치하고 관리하세요.

  1. 앱 프로젝트를 연 상태로 Xcode에서 File(파일) > Swift Packages(Swift 패키지) > Add Package Dependency(패키지 종속 항목 추가)로 이동합니다.
  2. 메시지가 표시되면 Firebase Apple 플랫폼 SDK 저장소를 추가합니다.
  3.   https://github.com/firebase/firebase-ios-sdk
      
  4. Firestore 라이브러리를 선택합니다.
  5. 완료되면 Xcode가 백그라운드에서 자동으로 종속 항목을 확인하고 다운로드하기 시작합니다.
Android
  1. 안내에 따라 Firebase를 Android 앱에 추가합니다.
  2. 모듈(앱 수준) Gradle 파일(일반적으로 app/build.gradle.kts 또는 app/build.gradle)에서 Android용 Firestore 라이브러리의 종속 항목을 선언합니다.
    implementation("com.google.firebase:firebase-firestore:24.9.1")

    앱에서 여러 Firebase 라이브러리를 사용하는 경우 앱의 Firebase 라이브러리 버전이 항상 호환되도록 Firebase Android BoM을 사용하는 것이 좋습니다.

    Kotlin 관련 라이브러리 모듈을 찾으시나요? 2023년 10월 출시부터 Kotlin과 Java 개발자 모두 기본 라이브러리 모듈을 사용할 수 있습니다. 자세한 내용은 이니셔티브에 관한 FAQ를 참조하세요.

Dart

  1. 아직 진행하지 않았으면 Flutter 앱에서 Firebase를 구성 및 초기화합니다.
  2. Flutter 프로젝트 루트에서 다음 명령어를 실행하여 플러그인을 설치합니다.
    flutter pub add cloud_firestore
  3. 완료되면 Flutter 애플리케이션을 다시 빌드합니다.
    flutter run
C++
  1. 안내에 따라 Firebase를 C++ 프로젝트에 추가합니다.
  2. Android용 C++ 인터페이스
    • Gradle 종속 항목 모듈(앱 수준) Gradle 파일(일반적으로 app/build.gradle)에 다음을 추가합니다.
              android.defaultConfig.externalNativeBuild.cmake {
                arguments "-DFIREBASE_CPP_SDK_DIR=$gradle.firebase_cpp_sdk_dir"
              }
      
              apply from: "$gradle.firebase_cpp_sdk_dir/Android/firebase_dependencies.gradle"
              firebaseCpp.dependencies {
                // earlier entries
                auth
                firestore
              }
              
    • 바이너리 종속 항목 마찬가지로 바이너리 종속 항목을 가져올 때 권장되는 방법은 CMakeLists.txt 파일에 다음을 추가하는 것입니다.
              add_subdirectory(${FIREBASE_CPP_SDK_DIR} bin/ EXCLUDE_FROM_ALL)
              set(firebase_libs firebase_auth firebase_firestore firebase_app)
              # Replace the target name below with the actual name of your target,
              # for example, "native-lib".
              target_link_libraries(${YOUR_TARGET_NAME_HERE} "${firebase_libs}")
              
  3. 데스크톱 통합을 설정하려면 C++ 프로젝트에 Firebase 추가를 참조하세요.
Unity
  1. 안내에 따라 Firebase를 Unity 프로젝트에 추가합니다.
  2. Unity 인터페이스를 사용하여 Android 빌드를 축소하도록 프로젝트를 구성합니다.
  3. Error while merging dex archives 메시지를 방지하기 위해 빌드를 축소해야 합니다.

    • 이 옵션은 Player Settings(플레이어 설정) > Android > Publishing Settings(게시 설정) > Minify(축소)에서 찾을 수 있습니다.
    • 옵션은 Unity 버전에 따라 다를 수 있으므로 공식 Unity 문서Firebase Unity 빌드 디버그 가이드를 참조하세요.
    • 축소를 사용 설정한 후에도 참조된 메서드의 개수가 여전히 한도를 초과하는 경우 또 다른 옵션은 다음 파일에서 multidex를 사용 설정하는 것입니다.
      • Player Settings(플레이어 설정)에서 Custom Gradle Template(커스텀 Gradle 템플릿)이 사용 설정된 경우 mainTemplate.gradle
      • 또는 Android 스튜디오를 사용하여 내보낸 프로젝트를 빌드하는 경우 모듈 수준 build.gradle 파일

Firestore 초기화

Firestore의 인스턴스를 초기화합니다.

웹 버전 9

// Initialize Firestore through Firebase
import { initializeApp } from "firebase/app"
import { getFirestore } from "firebase/firestore"
const firebaseApp = initializeApp({
  apiKey: '### FIREBASE API KEY ###',
  authDomain: '### FIREBASE AUTH DOMAIN ###',
  projectId: '### CLOUD FIRESTORE PROJECT ID ###'
});

const db = getFirestore();
`initializeApp`의 값은 웹 앱의 `firebaseConfig`에서 확인할 수 있습니다. 기기의 연결이 끊겨도 데이터를 유지하려면 오프라인 데이터 사용 설정 문서를 참조하세요.

웹 버전 8

// Initialize Firestore through Firebase
firebase.initializeApp({
  apiKey: '### FIREBASE API KEY ###',
  authDomain: '### FIREBASE AUTH DOMAIN ###',
  projectId: '### CLOUD FIRESTORE PROJECT ID ###'
});

var db = firebase.firestore();
`initializeApp`의 값은 웹 앱의 `firebaseConfig`에서 확인할 수 있습니다. 기기의 연결이 끊겨도 데이터를 유지하려면 오프라인 데이터 사용 설정 문서를 참조하세요.
Swift
참고: 이 제품은 watchOS 및 앱 클립 대상에서 사용할 수 없습니다.
import FirebaseCore
import FirebaseFirestore

FirebaseApp.configure()

let db = Firestore.firestore()
Objective-C
참고: 이 제품은 watchOS 및 앱 클립 대상에서 사용할 수 없습니다.
@import FirebaseCore;
@import FirebaseFirestore;

// Use Firebase library to configure APIs
[FIRApp configure];

FIRFirestore *defaultFirestore = [FIRFirestore firestore];
  
Kotlin+KTX
Android
  // Access a Firestore instance from your Activity
  val db = Firebase.firestore
자바
Android
// Access a Firestore instance from your Activity
  FirebaseFirestore db = FirebaseFirestore.getInstance();

Dart

db = FirebaseFirestore.instance;
C++
// Make sure the call to `Create()` happens some time before you call Firestore::GetInstance().
App::Create();
Firestore* db = Firestore::GetInstance();
Unity
using Firebase.Firestore;
using Firebase.Extensions;
FirebaseFirestore db = FirebaseFirestore.DefaultInstance;

데이터 추가

Firestore는 컬렉션에 저장되는 문서에 데이터를 저장합니다. 문서에 데이터를 처음 추가할 때 Firestore는 암시적으로 컬렉션과 문서를 만듭니다. 컬렉션이나 문서를 명시적으로 만들 필요가 없습니다.

다음 예시 코드를 사용해 새 컬렉션과 문서를 만듭니다.

웹 버전 9

import { collection, addDoc } from "firebase/firestore";

try {
  const docRef = await addDoc(collection(db, "users"), {
    first: "Ada",
    last: "Lovelace",
    born: 1815
  });
  console.log("Document written with ID: ", docRef.id);
} catch (e) {
  console.error("Error adding document: ", e);
}

웹 버전 8

db.collection("users").add({
    first: "Ada",
    last: "Lovelace",
    born: 1815
})
.then((docRef) => {
    console.log("Document written with ID: ", docRef.id);
})
.catch((error) => {
    console.error("Error adding document: ", error);
});
Swift
참고: 이 제품은 watchOS 및 앱 클립 대상에서 사용할 수 없습니다.
// Add a new document with a generated ID
var ref: DocumentReference? = nil
ref = db.collection("users").addDocument(data: [
  "first": "Ada",
  "last": "Lovelace",
  "born": 1815
]) { err in
  if let err = err {
    print("Error adding document: \(err)")
  } else {
    print("Document added with ID: \(ref!.documentID)")
  }
}
Objective-C
참고: 이 제품은 watchOS 및 앱 클립 대상에서 사용할 수 없습니다.
// Add a new document with a generated ID
__block FIRDocumentReference *ref =
    [[self.db collectionWithPath:@"users"] addDocumentWithData:@{
      @"first": @"Ada",
      @"last": @"Lovelace",
      @"born": @1815
    } completion:^(NSError * _Nullable error) {
      if (error != nil) {
        NSLog(@"Error adding document: %@", error);
      } else {
        NSLog(@"Document added with ID: %@", ref.documentID);
      }
    }];
Kotlin+KTX
Android
// Create a new user with a first and last name
val user = hashMapOf(
    "first" to "Ada",
    "last" to "Lovelace",
    "born" to 1815,
)

// Add a new document with a generated ID
db.collection("users")
    .add(user)
    .addOnSuccessListener { documentReference ->
        Log.d(TAG, "DocumentSnapshot added with ID: ${documentReference.id}")
    }
    .addOnFailureListener { e ->
        Log.w(TAG, "Error adding document", e)
    }
자바
Android
// Create a new user with a first and last name
Map<String, Object> user = new HashMap<>();
user.put("first", "Ada");
user.put("last", "Lovelace");
user.put("born", 1815);

// Add a new document with a generated ID
db.collection("users")
        .add(user)
        .addOnSuccessListener(new OnSuccessListener<DocumentReference>() {
            @Override
            public void onSuccess(DocumentReference documentReference) {
                Log.d(TAG, "DocumentSnapshot added with ID: " + documentReference.getId());
            }
        })
        .addOnFailureListener(new OnFailureListener() {
            @Override
            public void onFailure(@NonNull Exception e) {
                Log.w(TAG, "Error adding document", e);
            }
        });

Dart

// Create a new user with a first and last name
final user = <String, dynamic>{
  "first": "Ada",
  "last": "Lovelace",
  "born": 1815
};

// Add a new document with a generated ID
db.collection("users").add(user).then((DocumentReference doc) =>
    print('DocumentSnapshot added with ID: ${doc.id}'));
C++
// Add a new document with a generated ID
Future<DocumentReference> user_ref =
    db->Collection("users").Add({{"first", FieldValue::String("Ada")},
                                 {"last", FieldValue::String("Lovelace")},
                                 {"born", FieldValue::Integer(1815)}});

user_ref.OnCompletion([](const Future<DocumentReference>& future) {
  if (future.error() == Error::kErrorOk) {
    std::cout << "DocumentSnapshot added with ID: " << future.result()->id()
              << std::endl;
  } else {
    std::cout << "Error adding document: " << future.error_message() << std::endl;
  }
});
Unity
DocumentReference docRef = db.Collection("users").Document("alovelace");
Dictionary<string, object> user = new Dictionary<string, object>
{
	{ "First", "Ada" },
	{ "Last", "Lovelace" },
	{ "Born", 1815 },
};
docRef.SetAsync(user).ContinueWithOnMainThread(task => {
	Debug.Log("Added data to the alovelace document in the users collection.");
});

이제 users 컬렉션에 다른 문서를 추가합니다. 첫 번째 문서에는 나타나지 않는 키-값 쌍(중간 이름)이 문서에 포함된다는 점에 유의하세요. 컬렉션의 문서에는 다른 정보 집합이 포함될 수 있습니다.

웹 버전 9

// Add a second document with a generated ID.
import { addDoc, collection } from "firebase/firestore";

try {
  const docRef = await addDoc(collection(db, "users"), {
    first: "Alan",
    middle: "Mathison",
    last: "Turing",
    born: 1912
  });

  console.log("Document written with ID: ", docRef.id);
} catch (e) {
  console.error("Error adding document: ", e);
}

웹 버전 8

// Add a second document with a generated ID.
db.collection("users").add({
    first: "Alan",
    middle: "Mathison",
    last: "Turing",
    born: 1912
})
.then((docRef) => {
    console.log("Document written with ID: ", docRef.id);
})
.catch((error) => {
    console.error("Error adding document: ", error);
});
Swift
참고: 이 제품은 watchOS 및 앱 클립 대상에서 사용할 수 없습니다.
// Add a second document with a generated ID.
ref = db.collection("users").addDocument(data: [
  "first": "Alan",
  "middle": "Mathison",
  "last": "Turing",
  "born": 1912
]) { err in
  if let err = err {
    print("Error adding document: \(err)")
  } else {
    print("Document added with ID: \(ref!.documentID)")
  }
}
Objective-C
참고: 이 제품은 watchOS 및 앱 클립 대상에서 사용할 수 없습니다.
// Add a second document with a generated ID.
__block FIRDocumentReference *ref =
    [[self.db collectionWithPath:@"users"] addDocumentWithData:@{
      @"first": @"Alan",
      @"middle": @"Mathison",
      @"last": @"Turing",
      @"born": @1912
    } completion:^(NSError * _Nullable error) {
      if (error != nil) {
        NSLog(@"Error adding document: %@", error);
      } else {
        NSLog(@"Document added with ID: %@", ref.documentID);
      }
    }];
Kotlin+KTX
Android
// Create a new user with a first, middle, and last name
val user = hashMapOf(
    "first" to "Alan",
    "middle" to "Mathison",
    "last" to "Turing",
    "born" to 1912,
)

// Add a new document with a generated ID
db.collection("users")
    .add(user)
    .addOnSuccessListener { documentReference ->
        Log.d(TAG, "DocumentSnapshot added with ID: ${documentReference.id}")
    }
    .addOnFailureListener { e ->
        Log.w(TAG, "Error adding document", e)
    }
자바
Android
// Create a new user with a first, middle, and last name
Map<String, Object> user = new HashMap<>();
user.put("first", "Alan");
user.put("middle", "Mathison");
user.put("last", "Turing");
user.put("born", 1912);

// Add a new document with a generated ID
db.collection("users")
        .add(user)
        .addOnSuccessListener(new OnSuccessListener<DocumentReference>() {
            @Override
            public void onSuccess(DocumentReference documentReference) {
                Log.d(TAG, "DocumentSnapshot added with ID: " + documentReference.getId());
            }
        })
        .addOnFailureListener(new OnFailureListener() {
            @Override
            public void onFailure(@NonNull Exception e) {
                Log.w(TAG, "Error adding document", e);
            }
        });

Dart

// Create a new user with a first and last name
final user = <String, dynamic>{
  "first": "Alan",
  "middle": "Mathison",
  "last": "Turing",
  "born": 1912
};

// Add a new document with a generated ID
db.collection("users").add(user).then((DocumentReference doc) =>
    print('DocumentSnapshot added with ID: ${doc.id}'));
C++
db->Collection("users")
    .Add({{"first", FieldValue::String("Alan")},
          {"middle", FieldValue::String("Mathison")},
          {"last", FieldValue::String("Turing")},
          {"born", FieldValue::Integer(1912)}})
    .OnCompletion([](const Future<DocumentReference>& future) {
      if (future.error() == Error::kErrorOk) {
        std::cout << "DocumentSnapshot added with ID: "
                  << future.result()->id() << std::endl;
      } else {
        std::cout << "Error adding document: " << future.error_message()
                  << std::endl;
      }
    });
Unity
DocumentReference docRef = db.Collection("users").Document("aturing");
Dictionary<string, object> user = new Dictionary<string, object>
{
	{ "First", "Alan" },
	{ "Middle", "Mathison" },
	{ "Last", "Turing" },
	{ "Born", 1912 }
};
docRef.SetAsync(user).ContinueWithOnMainThread(task => {
	Debug.Log("Added data to the aturing document in the users collection.");
});

데이터 읽기

Firebase Console의 데이터 뷰어를 사용하여 Firestore에 추가한 데이터를 빠르게 확인합니다.

get 메서드를 사용하여 전체 컬렉션을 검색할 수도 있습니다.

웹 버전 9

import { collection, getDocs } from "firebase/firestore";

const querySnapshot = await getDocs(collection(db, "users"));
querySnapshot.forEach((doc) => {
  console.log(`${doc.id} => ${doc.data()}`);
});

웹 버전 8

db.collection("users").get().then((querySnapshot) => {
    querySnapshot.forEach((doc) => {
        console.log(`${doc.id} => ${doc.data()}`);
    });
});
Swift
참고: 이 제품은 watchOS 및 앱 클립 대상에서 사용할 수 없습니다.
db.collection("users").getDocuments() { (querySnapshot, err) in
  if let err = err {
    print("Error getting documents: \(err)")
  } else {
    for document in querySnapshot!.documents {
      print("\(document.documentID) => \(document.data())")
    }
  }
}
Objective-C
참고: 이 제품은 watchOS 및 앱 클립 대상에서 사용할 수 없습니다.
[[self.db collectionWithPath:@"users"]
    getDocumentsWithCompletion:^(FIRQuerySnapshot * _Nullable snapshot,
                                 NSError * _Nullable error) {
      if (error != nil) {
        NSLog(@"Error getting documents: %@", error);
      } else {
        for (FIRDocumentSnapshot *document in snapshot.documents) {
          NSLog(@"%@ => %@", document.documentID, document.data);
        }
      }
    }];
Kotlin+KTX
Android
db.collection("users")
    .get()
    .addOnSuccessListener { result ->
        for (document in result) {
            Log.d(TAG, "${document.id} => ${document.data}")
        }
    }
    .addOnFailureListener { exception ->
        Log.w(TAG, "Error getting documents.", exception)
    }
자바
Android
db.collection("users")
        .get()
        .addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
            @Override
            public void onComplete(@NonNull Task<QuerySnapshot> task) {
                if (task.isSuccessful()) {
                    for (QueryDocumentSnapshot document : task.getResult()) {
                        Log.d(TAG, document.getId() + " => " + document.getData());
                    }
                } else {
                    Log.w(TAG, "Error getting documents.", task.getException());
                }
            }
        });

Dart

await db.collection("users").get().then((event) {
  for (var doc in event.docs) {
    print("${doc.id} => ${doc.data()}");
  }
});
C++
Future<QuerySnapshot> users = db->Collection("users").Get();
users.OnCompletion([](const Future<QuerySnapshot>& future) {
  if (future.error() == Error::kErrorOk) {
    for (const DocumentSnapshot& document : future.result()->documents()) {
      std::cout << document << std::endl;
    }
  } else {
    std::cout << "Error getting documents: " << future.error_message()
              << std::endl;
  }
});
Unity
CollectionReference usersRef = db.Collection("users");
usersRef.GetSnapshotAsync().ContinueWithOnMainThread(task =>
{
  QuerySnapshot snapshot = task.Result;
  foreach (DocumentSnapshot document in snapshot.Documents)
  {
    Debug.Log(String.Format("User: {0}", document.Id));
    Dictionary<string, object> documentDictionary = document.ToDictionary();
    Debug.Log(String.Format("First: {0}", documentDictionary["First"]));
    if (documentDictionary.ContainsKey("Middle"))
    {
      Debug.Log(String.Format("Middle: {0}", documentDictionary["Middle"]));
    }

    Debug.Log(String.Format("Last: {0}", documentDictionary["Last"]));
    Debug.Log(String.Format("Born: {0}", documentDictionary["Born"]));
  }

  Debug.Log("Read all data from the users collection.");
});

데이터 보안

Firebase 인증Firestore 보안 규칙을 사용하여 Firestore의 데이터를 보호합니다.

다음은 시작하는 데 사용할 수 있는 기본 규칙 세트입니다. Firebase Console의 규칙 탭에서 보안 규칙을 수정할 수 있습니다.

인증 필요

// Allow read/write access on all documents to any user signed in to the application
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if request.auth != null;
    }
  }
}

잠금 모드

// Deny read/write access to all users under any conditions
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if false;
    }
  }
}

테스트 모드

// Allow read/write access to all users under any conditions
// Warning: **NEVER** use this rule set in production; it allows
// anyone to overwrite your entire database.
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if true;
    }
  }
}

웹, Android 또는 iOS 앱을 프로덕션에 배포하기 전에 앱 클라이언트만 Firestore 데이터에 액세스할 수 있도록 하는 단계를 수행합니다. 앱 체크 문서를 참조하세요.

동영상 가이드 보기

Firestore 모바일 및 웹 클라이언트 라이브러리 시작하기에 대한 자세한 안내는 다음 동영상 가이드 중 하나를 참조하세요.

iOS
Android

그 밖에도 많은 동영상을 Firebase YouTube 채널에서 확인할 수 있습니다.

다음 단계

다음 주제를 자세히 알아보세요.

  • Codelab - Android, iOS 또는 용 Codelab의 안내를 따라 실제 앱에서 Firestore를 사용하는 방법을 알아보세요.
  • 데이터 모델 - 계층적 데이터와 하위 컬렉션을 비롯한 Firestore에서 데이터가 구조화되는 방식을 자세히 알아보세요.
  • 데이터 추가 - Firestore에서 데이터를 만들고 업데이트하는 방법을 자세히 알아보세요.
  • 데이터 가져오기 - 데이터를 검색하는 방법을 자세히 알아보세요.
  • 단순 쿼리 및 복합 쿼리 실행 - 단순 쿼리 및 복합 쿼리 실행 방법을 알아보세요.
  • 쿼리 순서 지정 및 제한 - 쿼리에서 반환된 데이터의 순서를 지정하고 제한하는 방법을 알아보세요.