如何优雅地查询记录并在记录不存在时创建它?
How to elegantly query for a record and create it if it does not exist yet?
目标
startChat(partner_profile)
的目标是获取两个用户之间的聊天 ID,然后能够重定向到此聊天。
有两种不同的情况[=46=]:
他们之间的聊天已经存在
a) partner_profile
是第一个参与者
b) partner_profile
是第二个参与者
- 需要先创建他们之间的聊天
到目前为止我得到了什么
我知道如何为上面列出的每个案例获取 ID,但我不知道如何将它们全部组合起来。到目前为止,这是我的代码:
startChat(partner_profile) {
// case 1a
this.get('store').queryRecord('chat', {
first_participant: partner_profile.id
}).then(function(chat) {
let id = chat.get('id');
onSaveSuccess(id);
}).catch(function(){
});
// case 1b
this.get('store').queryRecord('chat', {
second_participant: partner_profile.id
}).then(function(chat) {
let id = chat.get('id');
onSaveSuccess(id);
return;
}).catch(function(){
// **error handling*
});
// case 2
let chat = this.get('store').createRecord('chat', {
second_participant: partner_profile
});
let onSaveSuccess = (id) => this.transitionToRoute('chats.chat',id);
chat.save()
.then(function(success) {
let id = success.get('id');
onSaveSuccess(id);
})
.catch((error) => {
// **error handling*
}
});
如何合并这些案例?
现在真的很难看,因为每个案例都被执行了,当然有两个失败了。我怎样才能以更好的方式做到这一点?有没有办法一次 get_or_create
一条记录(就像在 Django 中那样)?
感谢您的帮助:-)
编辑:更具体
更具体地说,我很难找到一种好方法来检查聊天是否已存在于我们的数据库中。看这个例子:
let existingChat = this.get('store').queryRecord('chat', {
first_participant: partner_profile.id
}).catch(function(){
});
if(!existingChat){
// ** check for case 1b and 2
};
在这个例子中,我首先查询商店的聊天。存储 returns 我在 existingChat
中保存的 Promise,当我想检查是否已存在与 if(!existingChat)
的聊天时,它尚未解决。
我不知道我是否有足够的代码,但这是我过去处理 get_or_create
的方式。
var database = [];
function getOrCreate(rowId) {
var rowIndex = database.findIndex(r => rowId === r.Id);
if (rowIndex < 0) {
database.push({
Id: rowId
});
return database[database.length - 1];
} else {
return database[rowIndex];
}
}
var item1 = getOrCreate(1);
var item2 = getOrCreate(2);
var item3 = getOrCreate(3);
var item4 = getOrCreate(1);
console.log(item4);
所以最好的方法是先查询该聊天,然后在找不到聊天时处理创建聊天(404):
import Route from '@ember/routing/route';
export default Route.extend({
// params is { first_participant, second_participant }
model(params) {
return this.store.queryRecord('chat', params)
.catch(() => {
// a 404 from the server would trigger a catch
return this.store.createRecord('chat', params);
});
}
});
基本上就是这个概念,但如果您需要创建两个聊天,它可能会涉及更多。在这种情况下,您可以使用 'rsvp'.
中的 all
或 hash
助手
import Route from '@ember/routing/route';
import { hash } from 'rsvp';
export default Route.extend({
// params is { first_participant, second_participant }
model(params) {
return this.store.queryRecord('chat', params)
.catch(() => {
// a 404 from the server would trigger a catch
return hash({
chatA: this.store.createRecord('chat', { first_participant: params.first_participant }),
chatB: this.store.createRecord('chat', { second_participant: params.second_participant })
});
});
}
});
以上会将您的 model
设置为 { chatA, chatB }
。您需要对 promise 执行的操作的复杂性还取决于您的后端 API 的复杂程度。有时这是一种气味,让您知道您的 API 不是最好的。
另一种更优雅的解决方案是使用async/await。
查看本指南:https://spin.atomicobject.com/2016/12/29/async-await-ember-project/
Async/await 已准备好迎接 IMO 的黄金时段。上面的例子看起来像这样:
import Route from '@ember/routing/route';
export default Route.extend({
// params is { first_participant, second_participant }
async model(params) {
let chat;
try {
chat = await this.store.queryRecord('chat', params);
} catch(e) {
// a 404 from the server would trigger a catch
chat = await this.store.createRecord('chat', params);
}
return chat;
}
});
这允许您以同步的方式编写异步代码,使其更易于编写和理解。
要开始使用上面的内容,您需要像上面的博客 post 指定的那样修改 ember-cli-build.js
文件,即
let app = new EmberApp(defaults, {
// Add options here
babel: {
includePolyfill: true
}
});
有关详细信息,我推荐这篇 in-depth 文章 http://rwjblue.com/2017/10/30/async-await-configuration-adventure/
这是根据@knownasilya 的建议重新组织的代码:
getChatFirstParticipant().then(transitionToChat)
.catch(() => {
getChatSecondParticipant().then(transitionToChat)
.catch(() => {
createChat(partner_profile).then(transitionToChat)
.catch((error) => {
// ** error handling**
});
});
目标
startChat(partner_profile)
的目标是获取两个用户之间的聊天 ID,然后能够重定向到此聊天。
有两种不同的情况[=46=]:
他们之间的聊天已经存在
a)
partner_profile
是第一个参与者b)
partner_profile
是第二个参与者- 需要先创建他们之间的聊天
到目前为止我得到了什么
我知道如何为上面列出的每个案例获取 ID,但我不知道如何将它们全部组合起来。到目前为止,这是我的代码:
startChat(partner_profile) {
// case 1a
this.get('store').queryRecord('chat', {
first_participant: partner_profile.id
}).then(function(chat) {
let id = chat.get('id');
onSaveSuccess(id);
}).catch(function(){
});
// case 1b
this.get('store').queryRecord('chat', {
second_participant: partner_profile.id
}).then(function(chat) {
let id = chat.get('id');
onSaveSuccess(id);
return;
}).catch(function(){
// **error handling*
});
// case 2
let chat = this.get('store').createRecord('chat', {
second_participant: partner_profile
});
let onSaveSuccess = (id) => this.transitionToRoute('chats.chat',id);
chat.save()
.then(function(success) {
let id = success.get('id');
onSaveSuccess(id);
})
.catch((error) => {
// **error handling*
}
});
如何合并这些案例?
现在真的很难看,因为每个案例都被执行了,当然有两个失败了。我怎样才能以更好的方式做到这一点?有没有办法一次 get_or_create
一条记录(就像在 Django 中那样)?
感谢您的帮助:-)
编辑:更具体
更具体地说,我很难找到一种好方法来检查聊天是否已存在于我们的数据库中。看这个例子:
let existingChat = this.get('store').queryRecord('chat', {
first_participant: partner_profile.id
}).catch(function(){
});
if(!existingChat){
// ** check for case 1b and 2
};
在这个例子中,我首先查询商店的聊天。存储 returns 我在 existingChat
中保存的 Promise,当我想检查是否已存在与 if(!existingChat)
的聊天时,它尚未解决。
我不知道我是否有足够的代码,但这是我过去处理 get_or_create
的方式。
var database = [];
function getOrCreate(rowId) {
var rowIndex = database.findIndex(r => rowId === r.Id);
if (rowIndex < 0) {
database.push({
Id: rowId
});
return database[database.length - 1];
} else {
return database[rowIndex];
}
}
var item1 = getOrCreate(1);
var item2 = getOrCreate(2);
var item3 = getOrCreate(3);
var item4 = getOrCreate(1);
console.log(item4);
所以最好的方法是先查询该聊天,然后在找不到聊天时处理创建聊天(404):
import Route from '@ember/routing/route';
export default Route.extend({
// params is { first_participant, second_participant }
model(params) {
return this.store.queryRecord('chat', params)
.catch(() => {
// a 404 from the server would trigger a catch
return this.store.createRecord('chat', params);
});
}
});
基本上就是这个概念,但如果您需要创建两个聊天,它可能会涉及更多。在这种情况下,您可以使用 'rsvp'.
中的all
或 hash
助手
import Route from '@ember/routing/route';
import { hash } from 'rsvp';
export default Route.extend({
// params is { first_participant, second_participant }
model(params) {
return this.store.queryRecord('chat', params)
.catch(() => {
// a 404 from the server would trigger a catch
return hash({
chatA: this.store.createRecord('chat', { first_participant: params.first_participant }),
chatB: this.store.createRecord('chat', { second_participant: params.second_participant })
});
});
}
});
以上会将您的 model
设置为 { chatA, chatB }
。您需要对 promise 执行的操作的复杂性还取决于您的后端 API 的复杂程度。有时这是一种气味,让您知道您的 API 不是最好的。
另一种更优雅的解决方案是使用async/await。 查看本指南:https://spin.atomicobject.com/2016/12/29/async-await-ember-project/
Async/await 已准备好迎接 IMO 的黄金时段。上面的例子看起来像这样:
import Route from '@ember/routing/route';
export default Route.extend({
// params is { first_participant, second_participant }
async model(params) {
let chat;
try {
chat = await this.store.queryRecord('chat', params);
} catch(e) {
// a 404 from the server would trigger a catch
chat = await this.store.createRecord('chat', params);
}
return chat;
}
});
这允许您以同步的方式编写异步代码,使其更易于编写和理解。
要开始使用上面的内容,您需要像上面的博客 post 指定的那样修改 ember-cli-build.js
文件,即
let app = new EmberApp(defaults, {
// Add options here
babel: {
includePolyfill: true
}
});
有关详细信息,我推荐这篇 in-depth 文章 http://rwjblue.com/2017/10/30/async-await-configuration-adventure/
这是根据@knownasilya 的建议重新组织的代码:
getChatFirstParticipant().then(transitionToChat)
.catch(() => {
getChatSecondParticipant().then(transitionToChat)
.catch(() => {
createChat(partner_profile).then(transitionToChat)
.catch((error) => {
// ** error handling**
});
});