Home > database >  How to merge new field value to an existing firestore document with flutter?
How to merge new field value to an existing firestore document with flutter?

Time:10-12

I am trying to assign a delivery agent to the order of products with a dropdown containing a list of delivery agents. I am trying to get documentId and merging new field value to the documentId which already exists. But as a result, I a getting a duplicate document with the same documentId containing filed values which I want to merge. kindly help me to understand what I am doing wrong.

enter image description here

full code order_view.dart

import 'package:flutter/material.dart';
import 'package:loading_animation_widget/loading_animation_widget.dart';
import '../../services/firebase_database.dart';
import '../widgets/snack_bar.dart';
import 'client_address.dart';
import 'dashboard.dart';
import 'package:url_launcher/url_launcher.dart';

class OrderView extends StatefulWidget {
  final Map<String, dynamic> orderData;
  final List<String> deliveryAgent;

  const OrderView(
      {Key? key, required this.orderData, required this.deliveryAgent})
      : super(key: key);

  @override
  State<OrderView> createState() => _OrderViewState();
}

class _OrderViewState extends State<OrderView> {
  final FirebaseDatabase _database = FirebaseDatabase();
  int index = 0;
  num totalAmount = 0;
  Map<String, dynamic> clientData = {};

  getcountTotalAmount() async {
    for (var item in widget.orderData["orders"]) {
      totalAmount = totalAmount   (item["productPrice"] * item["amount"]);
    }
    clientData = (await _database.getClientData(widget.orderData["userId"]))!;
    setState(() {});
  }

  @override
  void initState() {
    getcountTotalAmount();
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    bool _isloading = true;

    return Scaffold(
      backgroundColor: Colors.grey[200],
      appBar: AppBar(
        elevation: 4,
        title: const Text("Open Order"),
        actions: [
          TextButton(
            onPressed: () async {
              showDialog(
                  context: context,
                  builder: (context) {
                    return AlertDialog(
                      content: const Text(
                        "Are you sure you want to cancel this order?",
                        textAlign: TextAlign.center,
                      ),
                      actions: [
                        TextButton(
                            onPressed: () {
                              Navigator.pop(context);
                            },
                            child: const Text(
                              "No",
                              style:
                                  TextStyle(color: Colors.green, fontSize: 16),
                            )),
                        TextButton(
                            onPressed: () async {
                              // Navigator.pop(context);
                              showDialog(
                                  context: context,
                                  builder: (context) {
                                    return LoadingAnimationWidget.inkDrop(
                                      color: Colors.orange,
                                      size: 50,
                                    );
                                  });
                              await _database.removeOrder(
                                createTime: widget.orderData["createAt"],
                              );
                              Navigator.of(context).pop();
                              Navigator.of(context).pushAndRemoveUntil(
                                MaterialPageRoute(
                                    builder: (context) =>
                                        const AdminDashboard()),
                                ModalRoute.withName(''),
                              );

                              ScaffoldMessenger.of(context).showSnackBar(
                                snackBar(
                                    message: "Your order is removed",
                                    color: Colors.deepOrange),
                              );
                            },
                            child: const Text(
                              "Yes",
                              style: TextStyle(color: Colors.red, fontSize: 16),
                            )),
                      ],
                    );
                  });
            },
            child: const Text(
              "Cancel Order",
              style: TextStyle(
                color: Colors.red,
                fontWeight: FontWeight.w500,
                fontSize: 15,
              ),
            ),
          ),
        ],
      ),
      body: SizedBox(
        height: MediaQuery.of(context).size.height,
        width: MediaQuery.of(context).size.width,
        child: ListView(
          physics: const BouncingScrollPhysics(),
          children: [
            Container(
              color: Colors.white,
              child: ListView.separated(
                padding: const EdgeInsets.symmetric(vertical: 8),
                shrinkWrap: true,
                itemCount: widget.orderData["orders"].length,
                physics: const BouncingScrollPhysics(),
                itemBuilder: (context, index) {
                  return ListTile(
                    leading: Image.network(
                      widget.orderData["orders"][index]["productImage"],
                    ),
                    title: Text(
                      widget.orderData["orders"][index]["productTitle"],
                    ),
                    subtitle: SizedBox(
                      width: MediaQuery.of(context).size.width,
                      child: Row(
                        children: [
                          Text(
                            "₹ ${widget.orderData["orders"][index]["productPrice"]}",
                            style: const TextStyle(
                                color: Colors.green, fontSize: 12),
                          ),
                          const Text(" - "),
                          Text(
                            widget.orderData["orders"][index]["productUnit"],
                            style: const TextStyle(fontSize: 12),
                          ),
                          const Text(" x "),
                          Text(widget.orderData["orders"][index]["amount"]
                              .toString()),
                          const SizedBox(width: 5),
                          Text(
                            "Total ₹ ${widget.orderData["orders"][index]["productPrice"] * widget.orderData["orders"][index]["amount"]}",
                            style: const TextStyle(
                              color: Colors.green,
                              fontWeight: FontWeight.w600,
                              fontSize: 12,
                            ),
                          ),
                        ],
                      ),
                    ),
                  );
                },
                separatorBuilder: (BuildContext context, int index) {
                  return const Divider();
                },
              ),
            ),
            Container(
              padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 8),
              color: Colors.white,
              child: Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: [
                  Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      const Text('Delivery Slot'),
                      Text(
                        '${widget.orderData["deliverySlot"]}',
                        style: const TextStyle(
                            fontWeight: FontWeight.w500, fontSize: 16),
                      ),
                    ],
                  ),
                  Column(
                    crossAxisAlignment: CrossAxisAlignment.end,
                    children: [
                      Text(
                        "Delivery charge: ₹${widget.orderData["taxes"]}",
                      ),
                      Text(
                        "Total Price: ₹${totalAmount   widget.orderData["taxes"]}",
                        style: const TextStyle(
                            fontWeight: FontWeight.w500, fontSize: 16),
                      ),
                    ],
                  )
                ],
              ),
            ),
            const SizedBox(height: 16),
            Container(
              width: MediaQuery.of(context).size.width,
              padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 8),
              decoration: const BoxDecoration(
                color: Colors.white,
              ),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                mainAxisSize: MainAxisSize.min,
                children: [
                  Text(
                    'Ordered on: ${widget.orderData["createAt"]}',
                    style: const TextStyle(
                      fontWeight: FontWeight.w600,
                      fontSize: 14,
                    ),
                  ),
                  Text(
                    'Delivery at ${widget.orderData["addressType"]}',
                  ),
                  const SizedBox(
                    height: 16,
                  ),
                  Row(
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    children: [
                      SizedBox(
                        width: MediaQuery.of(context).size.width * 0.6,
                        child: Text(
                          'Address: ${widget.orderData["address"]}',
                        ),
                      ),
                      ElevatedButton(
                          onPressed: () {
                            Navigator.of(context).push(MaterialPageRoute(
                                builder: (context) => ClientAddress(
                                      lat: widget.orderData["latitude"],
                                      lag: widget.orderData["longitude"],
                                    )));
                          },
                          child: const Text('Open location'))
                    ],
                  ),
                ],
              ),
            ),
            const SizedBox(
              height: 16,
            ),
            Container(
              width: MediaQuery.of(context).size.width,
              padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 8),
              color: Colors.white,
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  const Text(
                    "Client Details",
                    style: TextStyle(
                      fontWeight: FontWeight.w600,
                      fontSize: 17,
                    ),
                  ),
                  Row(
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    children: [
                      SizedBox(
                        child: Text(
                          clientData["username"] ?? "",
                          style: const TextStyle(
                            fontWeight: FontWeight.w500,
                            fontSize: 15,
                          ),
                        ),
                      ),
                      SizedBox(
                        child: Text(
                          clientData["contact"] ?? "",
                          style: const TextStyle(
                            fontWeight: FontWeight.w500,
                            fontSize: 15,
                          ),
                        ),
                      ),
                      ElevatedButton.icon(
                        onPressed: () async {
                          String telephoneNumber = clientData["contact"];
                          Uri telephoneUrl = Uri.parse("tel:$telephoneNumber");
                          if (await canLaunchUrl(telephoneUrl)) {
                            await launchUrl(telephoneUrl);
                          }
                        },
                        icon: const Icon(
                          Icons.call,
                        ),
                        label: const Text('Call'),
                      )
                    ],
                  ),
                ],
              ),
            ),
            const SizedBox(
              height: 16,
            ),
            Container(
                width: MediaQuery.of(context).size.width,
                color: Colors.white,
                padding: const EdgeInsets.only(bottom: 8),
                child: Column(
                  children: [
                    Row(
                      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                      children: [
                        const Text(
                          "Delivery Agent",
                          style: TextStyle(
                            fontWeight: FontWeight.w500,
                            fontSize: 16,
                          ),
                        ),
                        DropdownButton(
                          items: widget.deliveryAgent
                              .map(
                                (e) => DropdownMenuItem(
                                  value: e,
                                  child: Text(e),
                                ),
                              )
                              .toList(),
                          onChanged: (val) {
                            setState(() {
                              index =
                                  widget.deliveryAgent.indexOf(val.toString());
                            });
                          },
                          isExpanded: false,
                          hint: Text(
                            widget.deliveryAgent[index],
                            style: const TextStyle(
                              fontWeight: FontWeight.w600,
                              fontSize: 15,
                            ),
                          ),
                        ),
                      ],
                    ),
                    ElevatedButton(
                        onPressed: () async {
                          bool results;
                          results = await _database.updateDeliveryAgent(
                            orderId: widget.orderData["orderId"],
                              deliveryAgent: widget.deliveryAgent[index].toString(),
                          );
                          if (results) {
                            setState(() {
                              _isloading = true;
                            });
                            ScaffoldMessenger.of(context).showSnackBar(
                              snackBar(
                                message: "Delivery agent assigned",
                                color: Colors.green,
                              ),
                            );
                          } else {
                            ScaffoldMessenger.of(context).showSnackBar(
                              snackBar(
                                message: "Error",
                                color: Colors.red,
                              ),
                            );
                          }
                          setState(() {
                            _isloading = true;
                          });
                        },
                        child: const Text('Assign Agent')),
                  ],
                )),
          ],
        ),
      ),
    );
  }
}

firebase_database.dart

CollectionReference<Map<String, dynamic>> testorders =
  FirebaseFirestore.instance.collection('testorders');

Future<bool> updateDeliveryAgent(
      {required String orderId, required String deliveryAgent}) async {
    try {
        testorders.doc(orderId).set({
          "deliveryAgent": {
            "agentName": deliveryAgent,
            "agentContact": '',
          },
        }, SetOptions(merge: true));
      return true;
    } catch (e) {
      if (kDebugMode) {
        print("error while assigning delivery agent: $e");
      }
    }
    return false;
  }

order.dart

Container(
    width: MediaQuery.of(context).size.width,
    color: Colors.white,
    padding: const EdgeInsets.only(bottom: 8),
    child: Column(
      children: [
        Row(
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
          children: [
            const Text(
              "Delivery Agent",
              style: TextStyle(
                fontWeight: FontWeight.w500,
                fontSize: 16,
              ),
            ),
            DropdownButton(
              items: widget.deliveryAgent
                  .map(
                    (e) => DropdownMenuItem(
                      value: e,
                      child: Text(e),
                    ),
                  )
                  .toList(),
              onChanged: (val) {
                setState(() {
                  index =
                      widget.deliveryAgent.indexOf(val.toString());
                });
              },
              isExpanded: false,
              hint: Text(
                widget.deliveryAgent[index],
                style: const TextStyle(
                  fontWeight: FontWeight.w600,
                  fontSize: 15,
                ),
              ),
            ),
          ],
        ),
        ElevatedButton(
            onPressed: () async {
              bool results;
              results = await _database.updateDeliveryAgent(
                orderId: widget.orderData["orderId"],
                  deliveryAgent: widget.deliveryAgent[index].toString(),
              );
              if (results) {
                setState(() {
                  _isloading = true;
                });
                ScaffoldMessenger.of(context).showSnackBar(
                  snackBar(
                    message: "Delivery agent assigned",
                    color: Colors.green,
                  ),
                );
              } else {
                ScaffoldMessenger.of(context).showSnackBar(
                  snackBar(
                    message: "Error",
                    color: Colors.red,
                  ),
                );
              }
              setState(() {
                _isloading = true;
              });
            },
            child: const Text('Assign Agent')),
      ],
    )),

CodePudding user response:

You cannot update a document ID once it's been defined.

See the following answer on alternative steps you can take: https://stackoverflow.com/a/52117929/9063088

CodePudding user response:

There is no way you can have duplicate document IDs inside the same collection. The screenshot shows two documents sharing the same ID but for sure one of them contains one or more white spaces at the end. So there are two situations, the orderId is correct and when you call set() it adds the document with a document ID that doesn't contains white spaces, while in the database there is already one present that contains white spaces, or vice versa. When it comes to document IDs, always call .trim() so it can remove the white spaces from the beginning and from the end.

  • Related