将角消防员图书馆放置 - II

>以前,我们创建了自己的firestore getters来返回适当的观察力,从而将诺言转变为可冷观察的诺言。今天,让我们继续使用其他命令,以正确地映射我们的数据。

>

映射数据

>现在我们不依赖rxfire返回映射的文档id,我们将创建自己的转换器。

“ firestore有一个内置的converter withconverter to conconter tor map to and firestore。不,谢谢。我们将从这里拿走。

getdoc()返回具有id的文档napshot,以及上述数据()。 getdocs()返回带有docs数组的querysnapshot,除其他外,这是返回的documentsnapshot对象。我们的类别模型现在看起来像这样:

// category.model

// mapping new instance
export interface icategory {
  name: string | null;
  id: string | null;
  key?: string;
}

// static class or export functions, it's a designers choice
export class category {
  public static newinstance(data: querydocumentsnapshot): icategory {
    if (data === null) {
      return null;
    }
    const d = data.data();
    return {
      id: data.id,
      name: d['name'],
      key: d['key']
    };
  }

  // receives querysnapshot and maps out the `data() ` and id
  public static newinstances(data: querysnapshot): icategory[] {
    // read docs array 
    return data.docs.map(n => category.newinstance(n));
  }

}

因此,现在的服务调用看起来像这样:

// category.service

 getcategories(params: iwhere[] = []): observable<icategory[]> {
    // ...
    return from(getdocs(_query)).pipe(
      map((res: querysnapshot) => {
        // here map
        return category.newinstances(res);
      })
    );
}
getcategory(id: string): observable<icategory> {
    return from(getdoc(doc(this.db, 'categories', id))).pipe(
      map((res: documentsnapshot) => {
        // map
        return category.newinstance(res);
      }),
    );
}

>让我们看看什么adddoc()返回。

>

创建文档

>我创建了一个带有名称和键的快速表单,添加类别,以及一个服务呼叫以创建类别:

// components/categories.list

addnew() {
    // read form:
    const newcat: partial<icategory> = this.fg.value;

    this.categoryservice.createcategory(newcat).subscribe({
      next: (res) => {
        // the category list should be updated here
       console.log(res);
      }
    });
}

>该服务有望返回可观察到的,以下内容可能无法将其删除,返回的对象是一个文档重新率,仅是对具有id创建的文档的引用。

// category.service
createcategory(category: partial<icategory>): observable<any> {
    return from(adddoc(collection(this.db, 'categories'), category)).pipe(
      map(res => {
        // i have nothing but id!
        return {...category, id: res.id};

      })
    );
}

>可能看起来不错,但是我不希望在不浏览映射器的情况下直接使用id,解决方案可以像单独的映射器一样简单,或者我们可以稍微适应newinstance

// category.model

// adjust newinstance to accept partial category
public static newinstance(data: documentsnapshot | partial<icategory>, id?: string): icategory {
    if (data === null) {
      return null;
    }

    const d = data instanceof documentsnapshot ? data.data() : data;
    return {
      id: data.id || id, // if data.id doesnt exist (as in adddoc)
      name: d['name'],
      key: d['key']
    };
}

然后,在服务呼叫中,我们通过返回的id

通过原始类别

// category.service

createcategory(category: partial<icategory>): observable<icategory> {

    return from(adddoc(collection(this.db, 'categories'), category)).pipe(
      map(res => {
        // update to pass category and res.id
        return category.newinstance(category, res.id);
      }),
    );

}

firestore语法的奇怪案例

>以下方法是如此相同,如果您不区分它们,您可能会在50岁之前失去头发。因此,我决定列出它们,然后忘记它们。

doc(this.db,“类别”,“ someid”)返回新文档或现有文档的文档retreference

doc(collection(this.db,'cantories'))返回新生成的id >

setdoc(_document_reference,{... newcategory},选项)设置文档数据,并在文档参考

中保存提供的id

adddoc(collection(this.db,'cantories'),{... newcategory});添加带有自动生成id的文档(这是doc(collection ...)然后setdoc())

    >的快捷方式

  • updatedoc(doc(this.db,'categories','staust_id'),partial_category)这会更新现有文档(doc(db ...)的快捷键(db ...),然后使用现有id)进行setdoc()
  • >从前两个开始激起了混乱,它们看起来是如此相似,但是它们是不同的>

  • // find document reference, or create it with new id
    const categoryref = doc(this.db, 'categories', '_somedocumentreferenceid');
    
    // create a document reference with auto generated id
    const categoryref = doc(collection(this.db, 'categories'));
    
  • 现在,返回的参考文档可用于创建实际文档,或对其进行更新。因此,预计将通过setdoc

  • 成功
  • // then use the returned reference to setdoc, to add a new document
    setdoc(categoryref, {name: 'bubbles', key: 'bubbles'});
    
    // pass partial document with options: merge to partially update an existing document
    setdoc(existingcategoryref, {name: 'bubble'}, {merge: true});
    
  • >如果文档不存在wit合并设置为true,它将创建一个带有部分数据的新文档。不好。小心。

安全的选项是最后两个:

>

// add a new documnet with a new generated id
adddoc(collection(this.db, 'categories'), {name: 'bubbles', key: 'bubbles'});

// update and existing document, this will throw an error if non existent
updatedoc(existingcategoryref, {name: 'bubbles'})

出于插图目的,这是创建新类别

的另一种方法

// an alternative way to create
createcategory(category: partial<icategory>): observable<icategory> {

    // new auto generated id
    const ref = doc(collection(this.db, 'categories'));

    return from(setdoc(ref, category)).pipe(
       map(_ => {
         // response is void, id is in original ref
         return category.newinstance(category, ref.id);
       })
    );
}

更新文档

>在上面的构建中,我为类别详细信息创建了一个快速表单以允许更新。我仍然会通过所有字段,但是我们总是可以通过部分字段。

>

// category.sevice

// id must be passed in category
updatecategory(category: partial<icategory>): observable<icategory> {
    return from(updatedoc(doc(this.db, 'categories', category.id), category)).pipe(
      map(_ => {
        // response is void
        // why do we do this? because you never know in the future what other changes you might need to make before returning
        return category.newinstance(category);
      })
    );
}

这是概念的证明,有一些方法可以拧紧松动的末端,例如强迫id通过,检查不存在的文档,返回不同的数据形状等。

>

使用它,收集表格,并捕获id:>

// categories/list.component
update(category: icategory) {
    // gather field values
    const cat: partial<icategory> = this.ufg.value;

    // make sure the id is passed
    this.categoryservice.updatecategory({...cat, id: category.id}).subscribe({
      next: (res) => {
        console.log(res); // this has the same category after update
      }
    });
  }

删除文档

这是直截了当的,我们可能会选择退还布尔值以获得成功。
>

// category.sevice

deletecategory(id: string): observable<boolean> {
    return from(deletedoc(doc(this.db, 'categories', id))).pipe(
      // response is void, but we might want to differentiate failures later
      map(_ => true)
    );
}

我们只是通过传递id

来称其为

// category/list.component

delete(category: icategory) {
    this.categoryservice.deletecategory(category.id).subscribe({
      next: (res) => {
        console.log('success!', res);
      }
    });
}

>没有直截了当的批量删除方式。让我们继续前进。

负责任地查询

>我们创建了一个iwher模型,以允许将任何查询传递到我们的类别列表。但是,我们应该控制在模型中查询的字段,并保护我们的组件免受现场变化的影响。我们还应该控制可以询问的内容,以及如何始终领先于火箱上的任何隐藏价格。

在我们的iwhere模型中,我们可以添加ifieldoptions模型。这是标签而不是名称的一个示例,以说明我们如何保护我们的组件免受火灾的变化。

// where.model

// the param fields object (yes its plural)
export interface ifieldoptions {
    label?: string; // exmaple
    key?: string;

    // other example fields
    month?: date;
    recent?: boolean;
    maxprice?: number;
}


// map fields to where conditions of the proper firestore keys

export const maplistoptions = (options?: ifieldoptions): iwhere[] => {

    let c: any[] = [];
    if (!options) return [];

    if (options.label) {
      // mapping label to name
      c.push({ fieldpath: 'name', opstr: '==', value: options.label });
    }

    if(options.key) {
      c.push({ fieldpath: 'key', opstr: '==', value: options.key });
    }
    // maxprice is a less than or equal operator
    if (options.maxprice) {
        c.push({ fieldpath: 'price', opstr: '<=', value: options.maxprice });
    }

    if (options.month) {
        // to implement, push only data of the same month
        c.push(...mapmonth(options.month));
    }

    if (options.recent) {
        const lastweek = new date();
        lastweek.setdate(lastweek.getdate() - 7);
        // things that happened since last week:
        c.push({ fieldpath: 'date', opstr: '>=', value: lastweek });
    }

    return c;
}

我们服务的更改就像这样

>

// category.sevice

// accept options of specific fields
getcategories(params?: ifieldoptions): observable<icategory[]> {
    // translate fields to where:
    const _where: any[] = (mapfieldoptions(fieldoptions))
        .map(n => where(n.fieldpath, n.opstr, n.value));

    // pass the where to query
    const _query = query(collection(this.db, this._url), ..._where);

    // ... getdocs
}

这是如何以最高价格获取一组文档的示例:

// example usage
something$ = someservice.getlist({maxprice: 344});

这更有意义。我添加了一个日期示例,请注意,即使firestore日期为type tymestamp,在javascript日期上的操作正常。该示例的想法是说明组件不应该真正知道实现的详细信息,因此获得“最新文档”,例如应该像这样的

>

// example
something$ = someservice.getlist({recent: true});

另一个示例是获取日期,firestore直接处理javascript日期:>

// where.model

const mapmonth = (month: date): iwhere[] => {
  const from = new date(month);
  const to = new date(month);

  from.setdate(1);
  from.sethours(0, 0, 0, 0);
  to.setmonth(to.getmonth() + 1);
  to.sethours(0, 0, 0, 0); // the edge of next month, is last day this month


  let c: iwhere[] = [

    { fieldpath: 'date', opstr: '>=', value: from },
    { fieldpath: 'date', opstr: '<=', value: to }
  ];

  return c;
};

这是按预期工作的。

时间戳

firestore参考时间戳。

在查询时,此类可能不会有所作为,但是如果您有一个日期字段,并且希望保存用户提供的日期,则最好使用firestore timestamp类进行转换。 firestore时间戳和javascript日期之间的差异是微妙的。如此微妙,我什至看不到它!我认为这是四舍五入的等级。

>

// somemodel

// use timestamp class to map from and to dates

const jsdate = new date();

// adddoc with
const newdata = {
    fbdate: timestamp.fromdate(jsdate)
}

// documentsnapshot returns data() with date field, the type is timestamp
// use todate to convert to js date
return data['fbdate'].todate();

firestore lite

firebase为firestore提供了简单crud的lite版本,到目前为止,我们仅使用了lite版本中的那些。我更改了所有
导入{...}来自'@angular/fire/firestore';

>
进入

导入{...}来自'@angular/fire/firestore/lite';

>

构建块的确很小。我个人项目中减少的主要部分从502 kb下降到352 kb。

拦截

>使用httpclient,我们使用了截距函数来添加加载效果,那么我们如何使用解决方案来做到这一点?我们可以将所有呼叫调查到一个照顾它的http服务。我们的新服务应该与此有关:

// http.service

@injectable({ providedin: 'root' })
export class httpservice {
  public run(fn: observable<any>): observable<any> {

    // show loader here
    showloader();

    // return function as is
    return fn
      .pipe(
        // hide loader
        finalize(() => hideloader()),
        // debug and catcherrors as well here
      );
  }
}

然后在服务中

// category.service

private httpservice = inject(httpservice);

getcategories(params?: iwhere[]): observable<icategory[]> {
    // ...
    // wrap in run
    return this.httpservice.run(from(getdocs(q)).pipe(
      map((res: querysnapshot) => {
        return category.newinstances(res);
      })
    ));
}

>上面的一个设计问题是类型检查的丢失,因为内部函数返回可观察到的。这可以用通用
修复

// http.service
// ...
public run<t>(fn: observable<any>): observable<t> {
    // ...
}

然后这样称呼:

>

// category.service
return this.httpService.run<ICategory[]>(from(getDocs(q)).pipe(
  map((res: QuerySnapshot) => {
    return Category.NewInstances(res);
  })
));

>查看我们先前使用状态管理创建的加载效果。我们需要的只是注入州服务,然后呼叫显示和隐藏。这使用了良好的ol'rxjs,我调查了信号,看不到它如何替换rxj,而不会造成大混乱。可能是一个罚款星期二。

就是这样。在50岁之前不要丢发头发。

你上火了吗?继续说话。还没有结束。

资源

stackblitz project

firesstore docs

相关文章

>在angular

中使用rxj创建负载效果

  • 将angular fire firestore库使用-ii- sekrab车库

  • 角燃箱炸弹群。以前,我们创建了自己的firestore获取器,以返回适当的观察力,从而将诺言转变为可感冒的诺言。今天,让我们继续使用其他命令,以正确地映射我们的数据。

garage.sekrab.com

以上就是将角消防员图书馆放置 - II的详细内容,更多请关注骃骐网【www.myinqi.com】。

相关推荐:

如何将文本放置在盒子外部下方?

本文档旨在解决如何使用 HTML 和 CSS 将文本放置在盒子(div)外部下方的问题。通过修改 CSS 样式,特别是调整边框的放置位置,可以轻松实现文本与盒子的相对位置控制。本文将提供详细的代码示例和解释,帮助开发者理解和应用这一技巧,从而优化网页布局。 在网页设计中,经常需要将文本放置在特定元素的下方,例如图片或容器。以下是一种常用的方法,通过调整 CSS 样式来实现这一效果。 核心思路: 关...

XSL-FO的static-content放置什么内容?

static-content用于定义页眉、页脚、页码等在每页固定位置重复显示的内容,通过flow-name与fo:region-before、fo:region-after等区域关联;2. flow负责文档主体内容的流动式排版,随页面分页自动延续,而static-content不参与内容流,仅在指定区域静态呈现;3. 实现页眉页脚需在fo:simple-page-master中定义region-b...

消防员模拟器Steam手机版下载教程

对于那些热爱模拟游戏并且对消防工作充满热情的玩家来说,消防员模拟器(firefighter simulator)是一款不容错过的游戏。它不仅能让你体验到作为一名消防员的紧张与刺激,还能在游戏中学习一些基本的消防安全知识。然而,如果你想在手机上体验这款游戏,可能会遇到一些挑战。本文将为你详细讲解如何通过steam平台下载并安装消防员模拟器的移动版本。 首先,你需要确保你的设备符合游戏的基本要求。虽然...

zlibirary电子图书馆最新有效网址

1、zlibirary电子图书入口2025最新☜☜☜☜☜点击保存2、zlibirary电子图书馆最新有效网址☜☜☜☜☜点击保存3、这些网站提供了Z-Library的大部分资源,并支持多种下载方式,例如一键下载、发送到Kindle等。 Z-Library 镜像站或相关渠道 https://clibrary.cn:包含了几乎所有 Z-Library 的资源,提供一键下载、发送到 Kindle、ipfs...

WordPress:限制是由工具还是开发人员放置的?

资深开发者眼中,WordPress常被误解为功能受限的平台。然而,我的经验恰恰相反。WordPress已发展成为一个强大的生态系统,足以构建复杂的商业应用。Gutenberg编辑器、完善的本地API以及与现代技术(如React)的集成,都展现了其无限潜力。 关键在于,WordPress只是我们工具箱中的一个工具。如同一位精通传统与分子料理的厨师,方法并非关键,最终成果才是。优秀的开发者,无论使用何...

Bytedance/Sonic:闪电般的JSON图书馆

微服务时代,毫秒必争。您是否曾经历过go服务在处理大量json请求时cpu飙升?tiktok工程师每天都面临着这一挑战——每天处理数十亿请求。他们的解决方案是sonic,一个正在改变go开发者游戏规则的json库。 JSON难题 每个Go开发者都熟悉 如果您是Go开发者,您可能使用过标准库encoding/json包。它好用,但速度并非最佳。现代网络服务或API每天都使用JSON,从REST AP...

参观金陵图书馆

参观金陵图书馆7月11日 星期天 雨 远看一块晶莹剔透的巨型玉石,旁边放着一块硕大的雨花石,这就是图书馆的主体建筑物。  一进大厅,圆形的透明天井顶棚中落下了一滴硕大的水滴,是悬挂在巨石方,散发出晶莹剔透的光芒----------水滴石穿的寓意。队员和家长们陆续到齐了。各个都穿着漂亮衣服,脸上挂着笑容。我们的队长刘净值是个尽职尽责的人,她让我们把心中不解的问题都检查一遍。吴从去...

英雄的消防员

现在,有很多工作,有帮助我们治病的医生,有教我们知识的老师,有公正办案的法官,还有为人们服务的警察``````而我最喜欢的就是救火的消防官兵。记得有一次,我在楼下玩,突然,有一阵浓烟,人们都飞快的跑过去,我也连忙跑过去,那栋十楼家浓言滚滚,在楼下的一位叔叔连忙拨打119,消防官兵开着消防车很快来到了起火地点,消防官兵迅速从消防车里拿出灭火器材,那根水管又粗又长,他们快速上了十楼去灭火,楼下的人们都...

未来图书馆

未来图书馆白银市平川区电厂学校  刘纪元2030年,我经过多年的研究,终于设计出了一种全新的图书馆,现在就让我们去看看吧。图书馆的外墙用十分漂亮的白色砌成,外形像一本翻开的书,所有的建筑材料都是用环保材料。一进门先坐到一个椅子上,它就立刻悬浮起来,同时有一个桌子就会摆到你面前。悬浮的桌椅就会带你去又宽又高的大书架选书,只要对大书架说出你想要的书名,书就会从大书架上飞出来,摆在你的书桌上,...

我与图书馆作文700字

  图书馆,那是我最喜欢去的地方。在清静温馨的图书馆里,知识的使者会降临到你的身边,使你感到轻松愉快。在图书馆里我们可以回忆古老的历史,也可以憧憬美好的未来;可以探索世界的奥秘;还可以得到学习的技巧和秘诀……以下是骃骐网小编为大家整理的700字我与图书馆作文,希望你们喜欢。我与图书馆700字作文篇1  我与图书馆  我们学校有两个图书馆,一个在三楼还有一个在二楼,以前我...