Google Sheet sang mô hình quan hệ: kế hoạch mô hình hóa từng bước
Chuyển Google Sheet sang mô hình quan hệ: các bước rõ ràng để nhận diện nhóm lặp, chọn khóa, ánh xạ quan hệ và tránh dữ liệu lộn xộn sau này.

Tại sao bảng tính trở nên lộn xộn khi biến thành cơ sở dữ liệu
Bảng tính rất hữu ích cho danh sách nhỏ. Bạn có thể thay cột nhanh, thêm ghi chú bất cứ đâu và sửa lỗi bằng mắt. Tuy nhiên tự do đó bắt đầu thất bại khi file trở thành nguồn dữ liệu chung.
Khi dữ liệu tăng, cùng những vấn đề xuất hiện lặp lại. Bạn thấy bản sao vì không có chỗ duy nhất lưu khách hàng hoặc sản phẩm. Bạn có giá trị mâu thuẫn vì hai hàng đưa thông tin khác nhau về cùng một thứ, như số điện thoại. Lọc và báo cáo trở nên khó chịu vì một số cột chứa danh sách ("Tags", "Products", "Attendees") hoặc trộn định dạng ("$1,200", "1200", "1.2k").
Việc chuyển từ Google Sheet sang mô hình quan hệ hướng tới an toàn. Cơ sở dữ liệu buộc cấu trúc rõ ràng hơn để bạn có thể truy vấn, kiểm tra và cập nhật dữ liệu mà không tạo ra mâu thuẫn mới.
Một mô hình tư duy hữu ích: một hàng nên đại diện cho một thực thể. Nếu một hàng đại diện cho một thỏa thuận, một khách hàng và một danh sách sản phẩm, việc cập nhật từng phần sau này sẽ rất đau đầu.
Một bài kiểm tra nhanh: có bao giờ một hàng cần hai giá trị cho cùng một trường không?
- Một đơn hàng có nhiều sản phẩm
- Một dự án có nhiều thành viên
- Một khách hàng có nhiều địa chỉ
Nếu câu trả lời là có, đó không phải là vấn đề “hàng rộng”. Đó là vấn đề “bảng riêng”. Khi bạn mô hình rõ ràng, bạn có thể xây form và quy tắc xác thực thay vì dựa vào chỉnh sửa thủ công mong manh.
Bắt đầu bằng cách định nghĩa chính xác ý nghĩa của sheet
Một bảng tính có thể trông có tổ chức nhưng vẫn mang ý nghĩa khác nhau với từng người. Trước khi chuyển Google Sheet sang mô hình quan hệ, hãy thống nhất sheet đang theo dõi điều gì.
Bắt đầu với kết quả cần đạt, không phải cột. Dữ liệu nên hỗ trợ quyết định gì: báo cáo doanh thu hàng tuần, danh sách ticket quá hạn, quy trình phân công follow-up, hay tra cứu nhanh khi gọi khách? Nếu bạn không thể gọi tên một quyết định, trường đó thường không thuộc về cơ sở dữ liệu.
Tiếp theo, kéo ra những danh từ ẩn trong tiêu đề và ghi chú. Chúng thường trở thành bảng: customers, orders, products, invoices, tickets, agents, locations. Nếu một cột trộn hai danh từ (như “Customer + Company”), bạn đang lưu nhiều thứ trong một chỗ.
Thống nhất định nghĩa sớm
Những khác biệt nhỏ về ý nghĩa sẽ thành những lần dọn dẹp lớn sau này. Rõ ràng về các cơ bản:
- "Order" là gì (một báo giá, một giao dịch đã thanh toán, hay cả hai)?
- "Customer" là ai (cá nhân, công ty, hay cả hai)?
- Một order có thể có nhiều sản phẩm không?
- Một email có thể thuộc nhiều khách hàng không?
- "Status" để chỉ gì (trạng thái hiện tại hay lịch sử)?
Ví dụ: nếu sheet của bạn có một hàng cho mỗi "Order" nhưng ô "Products" chứa danh sách phân cách bằng dấu phẩy, hãy quyết định liệu hàng đó đại diện cho checkout, shipment hay invoice. Mỗi lựa chọn dẫn đến schema khác nhau.
Đóng băng một bản copy của sheet gốc dưới dạng chỉ đọc. Bạn sẽ dùng nó để kiểm tra xem các bảng mới vẫn trả lời cùng các câu hỏi không.
Dọn sạch sheet để cấu trúc hiện ra
Trước khi chuyển Google Sheet sang mô hình quan hệ, hãy làm cho sheet trông giống dữ liệu hơn là báo cáo. Cơ sở dữ liệu cần hàng và cột nhất quán. Bố cục trang trí che giấu các mẫu bạn cần mô hình hóa.
Loại bỏ mẹo bố cục như ô gộp, nhiều hàng tiêu đề và các subtotal trong phạm vi dữ liệu. Giữ một hàng tiêu đề duy nhất rồi tiếp theo là các hàng bản ghi. Nếu cần tổng, để chúng trên tab tổng hợp riêng để không lẫn vào bản ghi thực tế.
Sau đó làm cho định dạng nhất quán trong từng cột. Cơ sở dữ liệu không thể đoán rằng “1/2/24”, “2024-02-01” và “Feb 1” là cùng một ngày. Điều tương tự áp dụng cho số điện thoại, tiền tệ và tên. Chọn một định dạng và dùng nó ở tất cả nơi, ngay cả khi cảm thấy nghiêm ngặt.
Một lượt dọn ngắn nhưng thường đáng công:
- Đảm bảo mỗi hàng đại diện cho một thứ (một order, một customer, một ticket).
- Loại bỏ hàng và cột khoảng trắng.
- Thay "N/A", "-", và chuỗi rỗng bằng một quy tắc duy nhất bạn sẽ giữ.
- Đánh dấu cột nào là tính toán và cột nào do người nhập.
Cuối cùng, gắn cờ bất kỳ ô nào chứa nhiều giá trị, như "red, blue, green" trong một cột. Chưa sửa schema ngay. Chỉ đánh dấu để nhớ rằng chúng sẽ thành các hàng riêng sau này.
Xác định các nhóm lặp và các trường che giấu danh sách
Dấu hiệu cảnh báo lớn nhất trong mô hình dữ liệu bảng tính là lặp lại. Sheet thường nhồi "nhiều hơn một thứ" vào một hàng bằng cách lặp cột hoặc đóng gói nhiều giá trị trong một ô. Cách đó hữu ích khi theo dõi nhanh nhưng vỡ khi cần lọc, báo cáo hoặc cập nhật nhất quán.
Các mẫu thường báo hiệu “nên là bảng khác”
Quét tìm những hình dạng sau:
- Các cột có đánh số như
Item 1,Item 2,Item 3hoặcPhone 1,Phone 2. - Khối lặp như trường địa chỉ lặp cho “Home” và “Work”.
- Ô có dấu phẩy, xuống dòng, hoặc “và” nối các giá trị (ví dụ: "Mouse, Keyboard, Monitor").
- Một cột trộn hai khái niệm, như "Approved 2025-01-10" hoặc "Alex (Manager)".
- Một hàng đại diện hai cấp cùng lúc, như hàng Order cố gắng lưu cả Order Items.
Ví dụ: nếu bộ theo dõi bán hàng dùng Order ID, Customer, Product 1, Qty 1, Product 2, Qty 2, bạn sẽ gặp bế tắc. Một số order có 1 món, một số có 8. Sheet sẽ phình ngang vô tận hoặc bắt đầu mất dữ liệu. Trong mô hình quan hệ, "Orders" là một bảng và "Order Items" là bảng khác, một hàng cho mỗi sản phẩm trong order.
Với "danh sách trong ô", xử lý mỗi giá trị như một bản ghi riêng. Một ô ghi “Email, SMS” thường cần một bảng riêng (hoặc bảng kết nối) để theo dõi kênh rõ ràng.
Các cột trộn lặng lẽ nhưng nguy hiểm không kém. Tách sớm để mỗi trường chứa một sự thật rõ ràng.
Tạo bảng từ các thực thể bạn tìm thấy
Khi bạn có thể gọi tên các thực thể trong sheet, chuyển mỗi thực thể thành một bảng. Spreadsheet của bạn sẽ không còn là một lưới lớn mà trở thành một tập các danh sách nhỏ, có mục đích.
Nếu một hàng trộn chi tiết của hai thứ khác nhau, nó có lẽ cần hai bảng. Một hàng trong bộ theo dõi bán hàng có thể chứa thông tin khách hàng (tên, điện thoại), thông tin đơn hàng (ngày, trạng thái) và thông tin sản phẩm (SKU, giá). Khách hàng không thay đổi mỗi khi đơn hàng thay đổi, và sản phẩm không phụ thuộc vào một đơn hàng duy nhất. Tách chúng tránh việc chỉnh sửa trùng lặp và giá trị không khớp.
Trước khi hoàn thiện, viết một câu ngắn mô tả mục đích của mỗi bảng. Nếu bạn không thể mô tả một bảng mà không nói "và thêm nữa", thường là quá rộng.
Một vài quy tắc thực tế:
- Giữ các thuộc tính mô tả cùng một thứ và có vòng đời giống nhau với nhau (tên khách hàng và email của khách hàng).
- Di chuyển bất cứ thứ gì có thể xuất hiện nhiều lần vào bảng riêng (nhiều order item, nhiều địa chỉ).
- Nếu một ô chứa danh sách (giá trị phân tách bằng dấu phẩy, cột lặp), đó là bảng riêng.
- Nếu hai tập trường thay đổi vì lý do khác nhau, tách chúng (trạng thái đơn hàng so với thông tin liên hệ khách hàng).
Sau đó đặt tên cột rõ ràng và nhất quán. Ưu tiên danh từ đơn giản và tránh nhãn mơ hồ như "Info" hay "Details".
Chọn khóa tồn tại ổn định theo thời gian
Chọn khóa chính cho mỗi bảng càng sớm càng tốt. Một khóa tốt là nhàm chán: không bao giờ thay đổi, luôn có, và chỉ xác định một hàng.
Khóa tự nhiên (giá trị thực tế) có thể dùng được, nhưng chỉ khi thật sự ổn định. SKU thường là khóa tự nhiên tốt vì được thiết kế để cố định. Email nghe có vẻ ổn định, nhưng người ta thay đổi email, chia sẻ hộp thư và tạo bản sao như “john@” và “john.work@”. Tên, số điện thoại và địa chỉ thay đổi và không đảm bảo duy nhất.
Mặc định an toàn là ID tự sinh (như customer_id, order_id). Giữ định danh thực tế như trường bình thường và thêm quy tắc duy nhất khi phù hợp với nghiệp vụ. Nếu email thay đổi, customer_id vẫn giữ nguyên và các đơn hàng liên quan vẫn trỏ đúng khách hàng.
Quy tắc khóa đơn giản:
- Dùng ID tự sinh khi định danh thực có thể thay đổi, bị thiếu hoặc được tái sử dụng.
- Dùng khóa tự nhiên chỉ khi bạn kiểm soát nó và nó được thiết kế để cố định (ví dụ SKU).
- Đánh dấu trường là unique chỉ khi trùng lặp thực sự sai.
- Cho phép NULL chỉ khi "không biết" là trạng thái hợp lệ; nếu không thì yêu cầu giá trị.
- Ghi rõ "unique" nghĩa là gì (unique trên bảng, trên công ty, hay trên khung thời gian).
Ví dụ: trong bảng Contacts, dùng contact_id làm khóa chính. Giữ email là unique chỉ nếu quy tắc của bạn là một contact tương ứng với một email. Cho phép phone trống vì không phải ai cũng có số điện thoại chia sẻ.
Ánh xạ mối quan hệ mà không đoán mò
Hầu hết lỗi nặng đến từ việc đoán xem các thực thể liên quan như thế nào. Dùng nguyên tắc đơn giản: nếu một hàng "sở hữu" nhiều thứ, đó là một quan hệ một-nhiều. Đặt khóa ngoại ở phía "nhiều".
Ví dụ: một Customer có thể có nhiều Orders. Bảng Orders nên lưu customer_id. Nếu bạn giữ danh sách số đơn hàng phân cách trong Customers, bạn sẽ nhanh chóng gặp bản sao và thiếu dữ liệu.
Nhiều-nhiều là bẫy phổ biến trong spreadsheet. Nếu một Order có nhiều Products và một Product có thể xuất hiện trong nhiều Orders, bạn cần một bảng kết nối (thường gọi là line items). Nó thường gồm order_id, product_id, cộng các trường như quantity và giá tại thời điểm mua.
Quan hệ một-một hiếm. Nó hợp lý khi dữ liệu thêm là tùy chọn hoặc tách riêng vì riêng tư hoặc hiệu năng (ví dụ: User và UserProfile). Đó là dấu hiệu cảnh báo nếu bạn tách bảng chỉ vì sheet có hai tab.
Lịch sử cần cấu trúc riêng. Nếu giá trị thay đổi theo thời gian (status, price, address), tránh ghi đè một cột đơn. Lưu thay đổi thành các hàng trong bảng lịch sử để bạn có thể trả lời “điều gì đúng vào ngày đó?”
Chuẩn hóa vừa đủ để tránh mâu thuẫn
Quy tắc đơn giản: lưu một sự thật ở một nơi. Nếu số điện thoại của khách hàng xuất hiện ở năm hàng, một người sẽ cập nhật bốn chỗ và bỏ sót một chỗ.
Chuẩn hóa theo ngôn ngữ đơn giản:
1NF, 2NF, 3NF theo cách thực tế
First normal form (1NF) nghĩa là mỗi ô chứa một giá trị. Nếu một cột có "red, blue, green" hoặc "SKU1|SKU2|SKU3", đó là danh sách ẩn. Tách nó thành các hàng trong bảng liên quan.
Second normal form (2NF) rõ nhất trong order items. Nếu bạn có OrderItems và khóa là (OrderID, ProductID), thì các trường như CustomerName không thuộc đó. Chúng phụ thuộc vào order, không phải product.
Third normal form (3NF) nghĩa là các trường không thuộc khóa không nên phụ thuộc vào các trường không thuộc khóa khác. Ví dụ: nếu bạn lưu ZipCode và City, và City được xác định bởi ZipCode, bạn có nguy cơ không khớp.
Một vài câu tự kiểm tra:
- Giá trị giống nhau có thể bị sửa ở nhiều nơi không?
- Một thay đổi có buộc bạn phải cập nhật nhiều hàng khác không?
- Bạn có lưu nhãn có thể suy ra từ một ID không?
- Tổng có được lưu cạnh các hàng nguyên gốc tạo nên nó không?
Khi chấp nhận denormalize
Denormalize chủ yếu cho báo cáo đọc nhiều, và hãy làm an toàn: coi bảng báo cáo là bản sao có thể xây lại. Giữ bảng đã chuẩn hóa làm nguồn chân lý.
Với giá trị dẫn xuất như tổng, số dư và trạng thái, đừng nhân bản trừ khi bạn có quy tắc rõ ràng để tính lại. Cách tiếp cận thực tế: lưu các giao dịch thô, tính tổng trong truy vấn, và chỉ cache tổng khi hiệu năng yêu cầu.
Những bẫy mô hình thường gặp gây dọn dẹp sau này
Hầu hết vấn đề "trong sheet thì ổn" xuất phát từ ý nghĩa, không phải công cụ. Mục tiêu là làm cho mỗi hàng nói một điều rõ ràng, theo cùng một cách, mọi lúc.
Bẫy thường gặp:
- Dùng tên làm ID. "John Smith" không phải định danh duy nhất và tên có thể thay đổi. Dùng ID sinh tự động (hoặc email/phone đã xác thực), và coi tên hiển thị là nhãn.
- Nhồi danh sách vào một ô. Trông đơn giản nhưng phá vỡ tìm kiếm, kiểm tra và báo cáo. Danh sách thuộc về bảng liên quan.
- Trộn trạng thái hiện tại với lịch sử. Một cột Status không thể cho cả trạng thái mới nhất lẫn cách nó thay đổi. Nếu thời gian quan trọng, lưu các thay đổi dưới dạng sự kiện có timestamp.
- Quá tải một bảng để mang nhiều ý nghĩa. Một sheet Contacts bao gồm customers, vendors và employees thường có các trường chỉ áp dụng cho một số hàng. Tách theo vai trò, hoặc giữ Person chung và thêm các bảng theo vai trò.
- Bỏ qua trường bắt buộc so với tùy chọn. Nếu trường quan trọng có thể để trống, bạn sẽ có hàng không thể join. Quyết định trường nào bắt buộc và áp dụng sớm.
Nếu Orders của bạn có cột như Item 1, Item 2, Item 3, đó là nhóm lặp. Lập kế hoạch cho bảng Orders và bảng OrderItems.
Danh sách kiểm tra nhanh trước khi chốt schema
Trước khi khoá schema, rà soát lần cuối cho rõ ràng. Hầu hết đau đầu sau này đến từ những lối tắt nhỏ lúc đầu tưởng vô hại.
Hỏi xem mỗi bảng trả lời một câu hỏi đơn giản hay không. "Customers" nên nghĩa là khách hàng, không phải khách hàng cộng với đơn hàng mới nhất cộng với ghi chú cuộc gọi. Nếu bạn không thể mô tả bảng trong một câu ngắn, nó đang trộn nhiều thứ.
Kiểm tra cuối:
- Bạn có thể chỉ ra cột (hoặc tập cột) xác định duy nhất mỗi hàng, ngay cả khi tên thay đổi không?
- Có ô nào chứa hơn một giá trị không (tags phân tách bằng dấu phẩy, nhiều email, cột Item1/Item2)? Nếu có, tách thành bảng con.
- Với mỗi quan hệ, nó có được lưu như khóa ngoại có chủ ý không? Với nhiều-nhiều, bạn có bảng kết nối chưa?
- Các trường quan trọng có quy tắc không (bắt buộc khi thiếu làm hỏng quy trình, unique khi trùng lặp gây hại)?
- Bạn có thể cập nhật một sự thật (địa chỉ khách hàng, giá sản phẩm, vai trò nhân viên) ở đúng một chỗ không?
Kiểm tra thực tế: tưởng tượng ai đó nhập cùng một khách hàng hai lần với đánh vần hơi khác. Nếu schema làm điều đó dễ, hãy thêm khóa tốt hơn hoặc quy tắc duy nhất.
Ví dụ: biến sheet theo dõi bán hàng thành các bảng sạch
Hãy hình dung sheet bán hàng mỗi hàng là một deal. Có cột Customer Name, Customer Email, Deal Amount, Stage, Close Date, Products (danh sách phân cách bằng dấu phẩy) và Notes (đôi khi nhiều ghi chú trong một ô).
Hàng đó che hai nhóm lặp: products (một deal có nhiều sản phẩm) và notes (một deal có nhiều ghi chú). Đây là điểm chuyển đổi sai phổ biến vì danh sách trong ô khó truy vấn và dễ mâu thuẫn.
Mô hình "sau" sạch sẽ phản ánh cách công việc thực sự vận hành:
- Customers (CustomerId, Name, Email)
- Deals (DealId, CustomerId, Amount, Stage, CloseDate)
- Products (ProductId, Name, SKU)
- DealProducts (DealId, ProductId, Quantity, UnitPrice)
- DealNotes (NoteId, DealId, NoteText, CreatedAt)
CustomerId, DealId, và ProductId là các định danh ổn định. DealProducts giải quyết quan hệ nhiều-nhiều: một deal có nhiều sản phẩm, một sản phẩm có thể xuất hiện trong nhiều deal. DealNotes giữ ghi chú riêng, tránh thành "Note 1, Note 2, Note 3".
Trước khi mô hình, báo cáo như “doanh thu theo sản phẩm” đồng nghĩa với việc tách chuỗi và hy vọng mọi người gõ tên đồng ý. Sau mô hình, đó là truy vấn đơn giản trên DealProducts join với Deals và Products.
Bước tiếp theo: từ schema đến ứng dụng hoạt động
Khi schema ổn trên giấy, chuyển nó vào cơ sở dữ liệu thực và kiểm thử với dữ liệu thật. Đừng nhập tất cả ngay. Nạp một lô nhỏ trước, sửa lỗi, rồi lặp lại.
Một thứ tự thực tế giữ rủi ro thấp:
- Tạo bảng và quan hệ.
- Nhập 50–200 hàng, kiểm tra tổng và rà soát vài bản ghi.
- Sửa vấn đề ánh xạ (cột sai, ID thiếu, bản sao), rồi nhập lại.
- Khi ổn định, nạp phần còn lại.
Thêm quy tắc xác thực sớm để thói quen bảng tính lộn xộn không quay lại. Làm các trường bắt buộc thực sự bắt buộc, giới hạn giá trị cho phép (như status), kiểm tra định dạng (ngày và email), và dùng khóa ngoại để không tạo order cho khách hàng không tồn tại.
Rồi thôi dùng sheet để cập nhật. Bảo vệ dữ liệu dễ hơn khi mọi người có form đơn giản và luồng làm việc rõ ràng.
Nếu bạn muốn biến schema thành công cụ nội bộ mà không viết code, AppMaster (appmaster.io) có thể giúp: bạn mô hình bảng và quan hệ trực quan, rồi sinh backend, web app và ứng dụng di động native sẵn sàng sản xuất từ cùng một mô hình.
Câu hỏi thường gặp
Bắt đầu khi bảng tính trở thành nguồn dữ liệu chung và bạn thấy trùng lặp, giá trị mâu thuẫn hoặc báo cáo trở nên đau đầu. Nếu bạn đang chiến đấu với các danh sách phân cách bằng dấu phẩy, cột Item 1/Item 2, hoặc việc phải sao chép/dán liên tục để sửa lỗi, chuyển sang mô hình quan hệ sẽ tiết kiệm thời gian nhanh chóng.
Nếu một hàng cần nhiều giá trị cho cùng một trường thì đó là một nhóm lặp lại. Ví dụ: nhiều sản phẩm trên cùng một đơn hàng, nhiều địa chỉ cho một khách hàng, hoặc nhiều người tham dự cho một sự kiện. Những trường hợp đó nên thành bảng con (hoặc bảng kết nối), chứ không phải thêm cột hoặc danh sách trong một ô.
Đóng băng một bản sao chỉ đọc của sheet gốc, rồi loại bỏ các ô gộp, hàng tiêu đề nhiều lớp và các hàng tổng phụ trong vùng dữ liệu. Đảm bảo mỗi cột nhất quán (một định dạng ngày, một định dạng tiền tệ, một cách biểu diễn giá trị rỗng) để bạn nhìn thấy cấu trúc thực trước khi mô hình hóa.
Mặc định là dùng ID tự sinh cho mọi bảng vì nó ổn định và không thay đổi khi người dùng cập nhật email, tên hoặc số điện thoại. Giữ các định danh thực tế (như email hoặc SKU) ở dạng trường bình thường và chỉ thêm quy tắc duy nhất khi việc trùng lặp thực sự có hại cho nghiệp vụ.
Xác định theo quyền sở hữu: nếu một khách hàng có nhiều đơn hàng, đặt customer_id trong bảng Orders. Nếu là nhiều-nhiều (orders và products), thêm một bảng kết nối như OrderItems chứa order_id, product_id cùng số lượng và giá tại thời điểm mua.
Nó có nghĩa là tránh mâu thuẫn. Lưu một sự thật ở một nơi duy nhất. Bạn không cần chuẩn hóa hoàn hảo, nhưng hãy loại bỏ các bản sao như cùng một số điện thoại của khách hàng xuất hiện ở nhiều hàng — điều đó sẽ khiến cập nhật bị lỗi và dữ liệu không nhất quán.
Tách thành các hàng thích hợp. Một ô như “Email, SMS” khó lọc và kiểm tra, và làm hỏng báo cáo. Tạo một bảng liên quan (hoặc bảng kết nối) nơi mỗi giá trị được lưu như một bản ghi riêng liên kết về hàng cha.
Tách “trạng thái hiện tại” và “lịch sử”. Giữ một trường trạng thái hiện tại nếu cần, nhưng lưu các thay đổi dưới dạng các hàng trong bảng lịch sử/sự kiện kèm dấu thời gian khi thời điểm thay đổi quan trọng. Điều này cho phép trả lời các câu như “trạng thái tháng trước là gì?” mà không phải đoán.
Nhập một lô nhỏ trước (khoảng 50–200 hàng), đối chiếu tổng và kiểm tra ngẫu nhiên các bản ghi so với bản sheet đã đóng băng. Sửa ánh xạ, ID thiếu và bản sao, rồi nhập lại. Chỉ nạp toàn bộ khi quy trình lặp lại được và đáng tin cậy.
Công cụ no-code có thể giúp khi bạn muốn biến schema thành ứng dụng có form, xác thực và luồng công việc, không chỉ bảng. Với AppMaster (appmaster.io), bạn có thể mô hình hóa bảng và quan hệ một cách trực quan rồi sinh backend sẵn sàng sản xuất, web app và ứng dụng di động native từ cùng một mô hình.


