检查 Flutter Firestore 中是不是已存在字段
Posted
技术标签:
【中文标题】检查 Flutter Firestore 中是不是已存在字段【英文标题】:Check if Field Already exists in Flutter Firestore检查 Flutter Firestore 中是否已存在字段 【发布时间】:2018-12-09 20:34:44 【问题描述】:我有一个名为 company
的集合。
所有公司都将像我的屏幕截图一样存储。
当我添加另一家公司时,我想检查 name
是否已经存在。
如何执行?
这里,“Nova”和“Tradetech”是两家公司。
当我再次尝试使用字段 name: "nova"
添加 “Nova” 时,我想显示一条通知:“公司已经存在!”。
【问题讨论】:
【参考方案1】:我已经用以下代码解决了这个问题,感谢您的帮助!
在我以前找到的以下代码中
1)文档是否存在?
2)密钥是否存在?
3)值是否存在?
SIMPLE METHOD
//////////////////////////////////////////////////////////////////////
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'dart:async';
String myText1 = 'temp1';
String myText2 = 'temp2';
String myText3 = 'temp3';
String myText4 = 'temp4';
String myText5 = 'temp5';
String myText6 = 'temp6';
StreamSubscription<DocumentSnapshot> subscription;
final DocumentReference documentReference =
Firestore.instance.document("company/Nova");
class Clean extends StatefulWidget
@override
_CleanState createState() => _CleanState();
class _CleanState extends State<Clean>
@override
void initState()
super.initState();
subscription = documentReference.snapshots().listen((datasnapshot)
//FINDING A SPECIFICDOCUMENT IS EXISTING INSIDE A COLLECTION
if (datasnapshot.exists)
setState(()
myText1 = "Document exist";
);
else if (!datasnapshot.exists)
setState(()
myText2 = "Document not exist";
);
//FINDING A SPECIFIC KEY IS EXISTING INSIDE A DOCUMENT
if (datasnapshot.data.containsKey("name"))
setState(()
myText3 = "key exists";
);
else if (!datasnapshot.data.containsKey("name"))
setState(()
myText4 = "key not exists";
);
//FINDING A SPECIFIC VALUE IS EXISTING INSIDE A DOCUMENT
if (datasnapshot.data.containsValue("nova"))
setState(()
myText5 = "value exists";
);
else if (!datasnapshot.data.containsValue("nova"))
setState(()
myText6 = "value not exists";
);
);
@override
Widget build(BuildContext context)
return Column(
children: <Widget>[
new Text(myText1),
new Text(myText2),
new Text(myText3),
new Text(myText4),
new Text(myText5),
new Text(myText6),
],
);
基于我现有代码的旧复杂方法 ///////////////////////////////////////// //////
概念
它有一个搜索栏,当你输入它会显示公司名称,即是否存在
Card
和 RaisedButton
。我在 Firestore 中使用小写字母以避免搜索错误。我用toLowercase()
强制TextFormField
输出为小写。您可以将其更改为您自己的文本格式。
代码
//if the name is not existing it will show a raised button so u can clcik on that to
//go to a COMPANY ADDING PAGE,otherwise it will only show a **CARD** so that you
//can't go to the next page to add your company
//code:
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'dart:async';
import './fullscreen.dart';
const blue = 0xFF3b78e7;
String filter = '';
StreamSubscription<DocumentSnapshot> subscription;
final TextEditingController _usercontroller = new TextEditingController();
class CheckAvail extends StatefulWidget
@override
HomeState createState() => HomeState();
class HomeState extends State<CheckAvail>
@override
Widget build(BuildContext context)
return Scaffold(
resizeToAvoidBottomPadding: false,
body: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
// CHILD1
new Flexible(
child: StreamBuilder(
stream: Firestore.instance
.collection('company')
.where('name', isGreaterThanOrEqualTo: filter.toLowerCase())
.limit(1)
.snapshots(),
builder: (BuildContext context,
AsyncSnapshot<QuerySnapshot> snapshot)
if (!snapshot.hasData)
return new Column(
children: <Widget>[
new Card(
elevation: 5.0,
child: new Image.asset('assets/progress.gif'),
)
],
);
else
return FirestoreListView1(documents: snapshot.data.documents);
,
),
),
new Card(
elevation: 0.0,
color: Colors.white,
shape: new RoundedRectangleBorder(
borderRadius: BorderRadius.circular(60.0)),
child: Container(
padding: new EdgeInsets.only(left: 8.0),
child: new TextField(
controller: _usercontroller,
onChanged: (String z)
setState(()
filter = z;
);
,
decoration: const InputDecoration(
hintText: "Search...",
hintStyle: TextStyle(
fontFamily: 'roboto',
color: Colors.black38,
fontSize: 16.0,
letterSpacing: -0.500),
fillColor: Colors.white,
border: InputBorder.none,
),
),
),
),
],
),
backgroundColor: Color(blue),
);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class FirestoreListView1 extends StatelessWidget
final List<DocumentSnapshot> documents;
FirestoreListView1(this.documents);
@override
Widget build(BuildContext context1)
return ListView.builder(
itemCount: documents.length,
padding: new EdgeInsets.all(1.0),
itemBuilder: (BuildContext context1, int index)
String name = documents[index].data['name'];
if (name.contains(filter.toLowerCase()) &&
name.length == filter.length)
return new Container(
padding: new EdgeInsets.only(top: 45.0),
child: new Card(
child: new Text(
"Error:Already a Company Exists with this name\nTry another name")),
);
else
return (filter.length >= 1)
? new Container(
padding: new EdgeInsets.only(top: 15.0),
child: new RaisedButton(
onPressed: () => Navigator.push(
context1,
new MaterialPageRoute(
builder: (context1) => new NextPage(
value1: name,
))),
disabledColor: Colors.white,
child: new Text(
"Good!You can use this company name",
),
),
)
: new Container(padding: new EdgeInsets.only(top: 250.0),
child: new Card(child: new Text("CHECK IF YOUR COMPANY NAME \n AVAILABLE OR NOT",style: new TextStyle(fontSize: 20.0),)),
);
);
【讨论】:
那真是太好了。请记住接受其中一个答案,因为这会将问题标记为已回答。你应该不 编辑你的title 像"[FIXED]",但接受一个答案 将问题标记为已回答。 @creativecreatorormaybenot 谢谢兄弟知道了,我不会再这样做了! 有一个按钮,看起来像一个勾号,一按就会变成绿色。那是您应该在投票下方接受答案的那个。例如。您可以接受您的答案以标记它解决了问题或标记其他人的答案。 使用此代码datasnapshot.data.containsKey("name")
总是打印出错误:Unhandled Exception: NoSuchMethodError: The method 'containsKey' was called on null.
datasnapshot.data.containsKey("name") 似乎已被弃用...error: The method 'containsKey' isn't defined for the type 'Object'.
【参考方案2】:
您可以简单地使用where
query 仅接收具有name
的文档,然后检查您是否收到文档。这是一个async
示例方法,可以执行您想知道的操作。
示例方法
Future<bool> doesNameAlreadyExist(String name) async
final QuerySnapshot result = await Firestore.instance
.collection('company')
.where('name', isEqualTo: name)
.limit(1)
.getDocuments();
final List<DocumentSnapshot> documents = result.documents;
return documents.length == 1;
如您所见,我仅接收文档,其中name
字段与给定的name
匹配。我还添加了limit(1)
以确保我不会不必要地检索 超过 1 个文档(这在 theory 中永远不会发生),然后我只是检查 @987654330 company
集合中的所有文档中的 @ 是否等于 1。如果它等于 1,则已经有家公司使用该名称,否则没有。
您也可以删除limit(1)
并检查documents.length > 1
,这也可以,但可能会检索到不必要的文档。
示例实现
@override
Widget build(BuildContext context)
return FutureBuilder(
future: doesNameAlreadyExist('nova'),
builder: (context, AsyncSnapshot<bool> result)
if (!result.hasData)
return Container(); // future still needs to be finished (loading)
if (result.data) // result.data is the returned bool from doesNameAlreadyExists
return Text('A company called "Nova" already exists.');
else
return Text('No company called "Nova" exists yet.');
,
);
在这里,我没有显示 错误消息,这也可以通过 示例方法 轻松实现。但是,使用了某些小部件的build
方法。这将是例如在对话中工作,但我决定这样做以使其简单易懂。 FutureBuilder
接收 doesNameAlreadyExist
,在这种情况下,您的问题中的名称为 "Nova",最后将返回一个 Text
小部件,说明该名称是否已存在。
小心
where
查询区分大小写。这意味着如果您键入例如,检查将不起作用。 "noVa" 而不是 "nova"。由于这可能对您很重要,您可以make use of this nice method,在其中创建一个不敏感的额外字段,例如所有字母都很小,然后你会像这样简单查询:
.where('name_insensitive', isEqualTo: name.toLowerCase())
【讨论】:
@creativecreator 可能不太感谢你的概念,我已经使用了你的概念和我现有的代码,然后我使用字符串长度来做出准确的发现。同时也避免了我一直使用的大小写敏感问题在我的firestore中以小写形式存储数据并在我的textformfiled中使用“toLowercase”。 我们可以在flutter中使用区分大小写和startswith方法吗 唯一的问题是我是否使用此逻辑进行插入(如果不存在)。可能存在竞争条件....所以我应该进行查找然后以事务方式插入。任何线索如何一举解决这一切? thanx 就是这么简单,也是最简单的一种 在这里,您必须为公司不存在的情况进行 2 次调用,Firestore 是否提供仅在“名称”不存在时插入的任何功能,如果已经存在则抛出异常?【参考方案3】:final QuerySnapshot result =
await Firestore.instance.collection('users').where('nickname', isEqualTo:
nickname).getDocuments();
final List < DocumentSnapshot > documents = result.documents;
if (documents.length > 0)
//exists
else
//not exists
【讨论】:
不应该是另一种方式吗?当documents.length == 0 //不存在 else //exists? 是的,我编辑了,if (documents.length > 0) //exists else //not exists 【参考方案4】:我知道我迟到了。 为未来的用户发布。 试试这个:
DocumentReference datab = db.collection("Company").document("Nova");
datab.get().addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>()
@Override
public void onSuccess(DocumentSnapshot documentSnapshot)
if(documentSnapshot.contains("name"))
Toast.makeText(YourActivity.this, "Child exixts.", Toast.LENGTH_SHORT).show();
else
Toast.makeText(YourActivity.this, "Doesnt exits.", Toast.LENGTH_SHORT).show();
);
【讨论】:
嗨,抱歉!这个问题太老了,thnkx 无法回复,顺便说一句,这可以简单地完成为>>> await documentref.get().the((doc)async int age = doc.data['age])//这里如果age==null所以该字段不可用, 不是 Flutter,是原生安卓代码!【参考方案5】:使用函数:
snapshot.data!.data()!.containsKey('key_name')
检查文档中是否存在字段。
PS。我刚刚在我的代码 RN 中使用了它,它可以工作
【讨论】:
以上是关于检查 Flutter Firestore 中是不是已存在字段的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 Flutter future<bool> 检查 Firestore 中是不是存在子集合
Flutter firestore - 检查文档ID是不是已经存在
如何使用 Flutter 在 Firestore 中检查多个文档中的特定值