Skip to content
This repository was archived by the owner on Sep 10, 2025. It is now read-only.

Commit e86c6a9

Browse files
updated
1 parent 328e385 commit e86c6a9

File tree

4 files changed

+165
-120
lines changed

4 files changed

+165
-120
lines changed

body.txt

Lines changed: 97 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,65 +1,108 @@
11

2-
This challenge involves styling a multi-level nested list using Tailwind CSS to create a visually appealing and easily navigable hierarchy. The goal is to achieve a clean, modern look with clear visual distinctions between the different list levels. We'll use Tailwind's utility classes for efficient and responsive styling.
3-
4-
5-
## Description of the Styling:
6-
7-
The nested list will have three levels:
8-
9-
* **Level 1:** Each top-level list item will have a bold title, a slightly larger font size, and a distinct background color.
10-
* **Level 2:** Sub-items will be indented, use a smaller font size, and have a subtle background color.
11-
* **Level 3:** Sub-sub-items will be further indented, use an even smaller font size, and have no background color.
12-
13-
We'll also aim for good spacing and readability using Tailwind's spacing utilities.
14-
15-
16-
## Full Code:
17-
18-
```html
19-
<ul class="list-disc pl-8">
20-
<li class="bg-gray-100 p-4 rounded mb-4">
21-
<h3 class="text-lg font-bold">Level 1 Item 1</h3>
22-
<ul class="list-disc pl-6">
23-
<li class="bg-gray-200 p-2 rounded mb-2">
24-
<p class="text-sm">Level 2 Item 1</p>
25-
<ul class="list-disc pl-6">
26-
<li class="text-xs">Level 3 Item 1</li>
27-
<li class="text-xs">Level 3 Item 2</li>
28-
</ul>
29-
</li>
30-
<li class="bg-gray-200 p-2 rounded mb-2">
31-
<p class="text-sm">Level 2 Item 2</p>
32-
</li>
33-
</ul>
34-
</li>
35-
<li class="bg-gray-100 p-4 rounded mb-4">
36-
<h3 class="text-lg font-bold">Level 1 Item 2</h3>
37-
<ul class="list-disc pl-6">
38-
<li class="bg-gray-200 p-2 rounded mb-2">
39-
<p class="text-sm">Level 2 Item 3</p>
40-
</li>
41-
</ul>
42-
</li>
43-
</ul>
2+
This document addresses a common challenge developers face when working with Firebase Firestore: efficiently handling large datasets, specifically in the context of storing and retrieving blog posts or similar content with potentially large amounts of text, images, or embedded media. The problem often manifests as slow read/write operations, exceeding Firestore's document size limits, or incurring excessive costs.
3+
4+
**Description of the Error:**
5+
6+
Trying to store entire blog posts (including rich text content, large images, etc.) within a single Firestore document can lead to several issues:
7+
8+
* **Document Size Limits:** Firestore has document size limits (currently 1 MB). Exceeding this limit results in write failures.
9+
* **Slow Retrieval:** Fetching a large document involves transferring a significant amount of data, resulting in slow load times for your application.
10+
* **Inefficient Queries:** Filtering and querying large documents is less efficient than working with smaller, well-structured data.
11+
* **Increased Costs:** Storing and retrieving large documents increases your Firestore usage and costs.
12+
13+
**Fixing the Problem Step-by-Step:**
14+
15+
The solution involves a common pattern: separating post data into smaller, more manageable documents. We'll use a strategy that splits the post into core metadata and separate storage for the rich text and media.
16+
17+
**1. Data Modeling:**
18+
19+
Instead of a single document per post, we'll use two:
20+
21+
* **`posts/{postId}`:** This document will store metadata like the title, author, publication date, short description, and a list of image URLs or references.
22+
* **`postContent/{postId}`:** This document will contain the rich text content of the post (potentially using a format like HTML or Markdown, possibly stored as a base64 string for simplicity). *Alternative:* This could be replaced with a separate storage service like Firebase Storage for even larger text content.
23+
24+
**2. Code Implementation (Node.js with the Firebase Admin SDK):**
25+
26+
```javascript
27+
const admin = require('firebase-admin');
28+
admin.initializeApp();
29+
const db = admin.firestore();
30+
31+
// Creating a new post
32+
async function createPost(postData) {
33+
const { title, author, date, shortDescription, content, images } = postData;
34+
const postId = db.collection('posts').doc().id;
35+
36+
// Store post metadata
37+
await db.collection('posts').doc(postId).set({
38+
title,
39+
author,
40+
date,
41+
shortDescription,
42+
images: images.map(image => image.url), // Store URLs from Firebase Storage
43+
});
44+
45+
// Store post content (adjust according to your content format)
46+
await db.collection('postContent').doc(postId).set({
47+
content,
48+
});
49+
50+
return postId;
51+
}
52+
53+
54+
// Retrieving a post
55+
async function getPost(postId) {
56+
const postDoc = await db.collection('posts').doc(postId).get();
57+
const contentDoc = await db.collection('postContent').doc(postId).get();
58+
59+
if (!postDoc.exists || !contentDoc.exists) {
60+
return null;
61+
}
62+
63+
const postData = postDoc.data();
64+
postData.content = contentDoc.data().content; // Merge content
65+
66+
return postData;
67+
}
68+
69+
//Example Usage
70+
const newPost = {
71+
title: "My Awesome Post",
72+
author: "John Doe",
73+
date: new Date(),
74+
shortDescription: "A brief summary of my post.",
75+
content: "<p>This is the rich text content of my post.</p>",
76+
images: [{ url: "gs://my-bucket/image1.jpg", name: "image1" }] //Replace with actual URLs from Firebase Storage.
77+
78+
};
79+
80+
createPost(newPost)
81+
.then(postId => console.log("Post created with ID:", postId))
82+
.catch(error => console.error("Error creating post:", error));
83+
84+
85+
getPost('somePostId')
86+
.then(post => console.log("Retrieved Post:", post))
87+
.catch(error => console.error("Error getting post:", error))
4488

4589
```
4690

47-
## Explanation:
4891

49-
* **`list-disc`**: This Tailwind class adds a disc bullet point to each list item.
50-
* **`pl-8`, `pl-6`**: These classes add padding to the left, creating the indentation for each level. The values (8 and 6) represent units in Tailwind's spacing system.
51-
* **`bg-gray-100`, `bg-gray-200`**: These classes set the background color for different levels using Tailwind's color palette.
52-
* **`p-4`, `p-2`**: These classes add padding to the list items.
53-
* **`rounded`**: This class adds rounded corners to the list items.
54-
* **`mb-4`, `mb-2`**: These classes add margin to the bottom, creating spacing between list items.
55-
* **`text-lg`, `text-sm`, `text-xs`**: These classes set the font sizes for each level.
56-
* **`font-bold`**: This class makes the Level 1 titles bold.
92+
**3. Firebase Storage for Images (Optional but Recommended):**
93+
94+
For images, use Firebase Storage instead of embedding them directly in Firestore. This keeps your Firestore data lean and allows for efficient image serving. You would upload the images to Storage and store only the download URLs in your `posts` documents.
95+
96+
**Explanation:**
97+
98+
This approach separates concerns, keeping metadata small and efficiently handling the potentially large content. Queries will be faster and more efficient because you're working with smaller documents. You can easily add more fields to your `posts` document for easier filtering and searching. This strategy scales better and reduces costs associated with storing and retrieving large amounts of data.
5799

58100

59-
## Links to Resources to Learn More:
101+
**External References:**
60102

61-
* **Tailwind CSS Documentation:** [https://tailwindcss.com/docs](https://tailwindcss.com/docs) This is the official documentation for Tailwind CSS, providing comprehensive information on all its utility classes and features.
62-
* **Learn CSS Grid:** [https://css-tricks.com/snippets/css/complete-guide-grid/](https://css-tricks.com/snippets/css/complete-guide-grid/) (While not directly used here, understanding CSS Grid is beneficial for advanced layout techniques).
103+
* [Firebase Firestore Documentation](https://firebase.google.com/docs/firestore)
104+
* [Firebase Storage Documentation](https://firebase.google.com/docs/storage)
105+
* [Firebase Admin SDK Node.js](https://firebase.google.com/docs/admin/setup)
63106

64107

65108
Copyrights (c) OpenRockets Open-source Network. Free to use, copy, share, edit or publish.

errors/javascript/efficiently-storing-and-retrieving-large-post-data-in-firebase-firestore/README.md

Lines changed: 66 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,108 +1,110 @@
11
# 🐞 Efficiently Storing and Retrieving Large Post Data in Firebase Firestore
22

33

4-
## Problem Description: Performance Issues with Large Post Data
4+
This document addresses a common challenge developers face when working with Firebase Firestore: efficiently handling large datasets, specifically in the context of storing and retrieving blog posts or similar content with potentially large amounts of text, images, or embedded media. The problem often manifests as slow read/write operations, exceeding Firestore's document size limits, or incurring excessive costs.
55

6-
A common problem when using Firebase Firestore to store and retrieve posts, especially those containing rich media (images, videos), is performance degradation. Storing large amounts of data within a single document can lead to slow read and write operations, exceeding Firestore's document size limits (currently 1 MB), and impacting the user experience. This issue manifests as slow loading times for posts, especially when retrieving multiple posts or posts with many attachments.
6+
**Description of the Error:**
77

8-
## Solution: Data Denormalization and Optimized Data Structure
8+
Trying to store entire blog posts (including rich text content, large images, etc.) within a single Firestore document can lead to several issues:
99

10-
The solution lies in optimizing the data structure and utilizing data denormalization techniques. Instead of storing all post data (text, images, videos, user details, etc.) within a single document, we'll break it down into smaller, more manageable units. This reduces the size of individual documents and improves query performance.
10+
* **Document Size Limits:** Firestore has document size limits (currently 1 MB). Exceeding this limit results in write failures.
11+
* **Slow Retrieval:** Fetching a large document involves transferring a significant amount of data, resulting in slow load times for your application.
12+
* **Inefficient Queries:** Filtering and querying large documents is less efficient than working with smaller, well-structured data.
13+
* **Increased Costs:** Storing and retrieving large documents increases your Firestore usage and costs.
1114

12-
## Step-by-Step Code Solution (JavaScript)
15+
**Fixing the Problem Step-by-Step:**
1316

14-
This example uses JavaScript with the Firebase Admin SDK. Adapt as needed for your client-side implementation. We'll focus on storing post text and image URLs; extending it to include videos is straightforward.
17+
The solution involves a common pattern: separating post data into smaller, more manageable documents. We'll use a strategy that splits the post into core metadata and separate storage for the rich text and media.
1518

16-
**1. Project Setup:**
19+
**1. Data Modeling:**
1720

18-
Ensure you have the Firebase Admin SDK installed:
21+
Instead of a single document per post, we'll use two:
1922

20-
```bash
21-
npm install firebase-admin
22-
```
23+
* **`posts/{postId}`:** This document will store metadata like the title, author, publication date, short description, and a list of image URLs or references.
24+
* **`postContent/{postId}`:** This document will contain the rich text content of the post (potentially using a format like HTML or Markdown, possibly stored as a base64 string for simplicity). *Alternative:* This could be replaced with a separate storage service like Firebase Storage for even larger text content.
2325

24-
Initialize the Firebase Admin SDK:
26+
**2. Code Implementation (Node.js with the Firebase Admin SDK):**
2527

2628
```javascript
2729
const admin = require('firebase-admin');
2830
admin.initializeApp();
2931
const db = admin.firestore();
30-
```
3132

32-
**2. Post Data Structure:**
33+
// Creating a new post
34+
async function createPost(postData) {
35+
const { title, author, date, shortDescription, content, images } = postData;
36+
const postId = db.collection('posts').doc().id;
37+
38+
// Store post metadata
39+
await db.collection('posts').doc(postId).set({
40+
title,
41+
author,
42+
date,
43+
shortDescription,
44+
images: images.map(image => image.url), // Store URLs from Firebase Storage
45+
});
3346

34-
Instead of a single document containing everything, we create two collections:
47+
// Store post content (adjust according to your content format)
48+
await db.collection('postContent').doc(postId).set({
49+
content,
50+
});
3551

36-
* `posts`: Stores concise post metadata (ID, title, timestamp, author ID, etc.).
37-
* `postImages`: Stores image URLs associated with posts (post ID as a field).
52+
return postId;
53+
}
3854

39-
**3. Storing a Post:**
4055

41-
```javascript
42-
async function createPost(postData) {
43-
// Extract image URLs
44-
const imageUrls = postData.images || [];
45-
delete postData.images; //Remove from the main object
56+
// Retrieving a post
57+
async function getPost(postId) {
58+
const postDoc = await db.collection('posts').doc(postId).get();
59+
const contentDoc = await db.collection('postContent').doc(postId).get();
4660

47-
const postRef = await db.collection('posts').add(postData);
48-
const postId = postRef.id;
61+
if (!postDoc.exists || !contentDoc.exists) {
62+
return null;
63+
}
4964

50-
// Store image URLs separately
51-
const imagePromises = imageUrls.map(url => {
52-
return db.collection('postImages').add({ postId: postId, imageUrl: url });
53-
});
65+
const postData = postDoc.data();
66+
postData.content = contentDoc.data().content; // Merge content
5467

55-
await Promise.all(imagePromises); // Ensures all images are stored before proceeding
56-
console.log('Post created with ID:', postId);
68+
return postData;
5769
}
5870

59-
// Example usage
71+
//Example Usage
6072
const newPost = {
61-
title: 'My Awesome Post',
62-
content: 'This is a long post with multiple images.',
63-
authorId: 'user123',
64-
timestamp: admin.firestore.FieldValue.serverTimestamp(),
65-
images: ['url1.jpg', 'url2.png', 'url3.gif']
66-
};
67-
73+
title: "My Awesome Post",
74+
author: "John Doe",
75+
date: new Date(),
76+
shortDescription: "A brief summary of my post.",
77+
content: "<p>This is the rich text content of my post.</p>",
78+
images: [{ url: "gs://my-bucket/image1.jpg", name: "image1" }] //Replace with actual URLs from Firebase Storage.
6879

69-
createPost(newPost).catch(console.error);
80+
};
7081

71-
```
82+
createPost(newPost)
83+
.then(postId => console.log("Post created with ID:", postId))
84+
.catch(error => console.error("Error creating post:", error));
7285

7386

74-
**4. Retrieving a Post:**
87+
getPost('somePostId')
88+
.then(post => console.log("Retrieved Post:", post))
89+
.catch(error => console.error("Error getting post:", error))
7590

76-
```javascript
77-
async function getPost(postId) {
78-
const postDoc = await db.collection('posts').doc(postId).get();
79-
if (!postDoc.exists) {
80-
return null;
81-
}
82-
83-
const post = postDoc.data();
84-
const imagesSnapshot = await db.collection('postImages')
85-
.where('postId', '==', postId)
86-
.get();
91+
```
8792

88-
post.images = imagesSnapshot.docs.map(doc => doc.data().imageUrl);
89-
return post;
90-
}
9193

92-
getPost('yourPostId').then(post => console.log(post)).catch(console.error);
93-
```
94+
**3. Firebase Storage for Images (Optional but Recommended):**
9495

96+
For images, use Firebase Storage instead of embedding them directly in Firestore. This keeps your Firestore data lean and allows for efficient image serving. You would upload the images to Storage and store only the download URLs in your `posts` documents.
9597

96-
## Explanation
98+
**Explanation:**
9799

98-
This approach utilizes data denormalization. While we store some redundancy (the `postId` appears in both collections), it significantly improves query performance. Retrieving a single post now involves fetching only one small document from `posts` and a query on `postImages` which is optimized. Large image data isn't stored directly in `posts` documents, avoiding size limitations and improving read speed.
100+
This approach separates concerns, keeping metadata small and efficiently handling the potentially large content. Queries will be faster and more efficient because you're working with smaller documents. You can easily add more fields to your `posts` document for easier filtering and searching. This strategy scales better and reduces costs associated with storing and retrieving large amounts of data.
99101

100102

101-
## External References:
103+
**External References:**
102104

103-
* [Firestore Data Modeling](https://firebase.google.com/docs/firestore/modeling/design): Firebase's official documentation on data modeling best practices.
104-
* [Firestore Limits](https://firebase.google.com/docs/firestore/quotas): Understanding Firestore's quotas and limitations, including document size.
105-
* [Firebase Admin SDK](https://firebase.google.com/docs/admin/setup): Setting up and using the Firebase Admin SDK.
105+
* [Firebase Firestore Documentation](https://firebase.google.com/docs/firestore)
106+
* [Firebase Storage Documentation](https://firebase.google.com/docs/storage)
107+
* [Firebase Admin SDK Node.js](https://firebase.google.com/docs/admin/setup)
106108

107109

108110
Copyrights (c) OpenRockets Open-source Network. Free to use, copy, share, edit or publish.

0 commit comments

Comments
 (0)