Untuk seseorang yang memiliki masalah dengan populatedan juga ingin melakukan ini:
- mengobrol dengan teks sederhana & balasan cepat (gelembung)
- 4 koleksi database untuk chatting:
clients, users, rooms, messasges.
- struktur DB pesan yang sama untuk 3 jenis pengirim: bot, pengguna & klien
refPathatau referensi dinamis
populatedengan pathdan modelopsi
- gunakan
findOneAndReplace/ replaceOnedengan$exists
- buat dokumen baru jika dokumen yang diambil tidak ada
KONTEKS
Tujuan
- Simpan pesan teks sederhana baru ke database & isi dengan data pengguna atau klien (2 model berbeda).
- Simpan pesan quickReplies baru ke database dan isi dengan data pengguna atau klien.
- Simpan setiap pesan jenis pengirimnya:
clients, users& bot.
- Isi hanya pesan yang memiliki pengirim
clientsatau usersdengan Model Mongoose-nya. _sender type client models is clients, for user is users.
Skema pesan :
const messageSchema = new Schema({
room: {
type: Schema.Types.ObjectId,
ref: 'rooms',
required: [true, `Room's id`]
},
sender: {
_id: { type: Schema.Types.Mixed },
type: {
type: String,
enum: ['clients', 'users', 'bot'],
required: [true, 'Only 3 options: clients, users or bot.']
}
},
timetoken: {
type: String,
required: [true, 'It has to be a Nanosecond-precision UTC string']
},
data: {
lang: String,
// Format samples on https://docs.chatfuel.com/api/json-api/json-api
type: {
text: String,
quickReplies: [
{
text: String,
// Blocks' ids.
goToBlocks: [String]
}
]
}
}
mongoose.model('messages', messageSchema);
LARUTAN
Permintaan API sisi server saya
Kode saya
Fungsi utilitas (dalam chatUtils.jsfile) untuk mendapatkan jenis pesan yang ingin Anda simpan:
/**
* We filter what type of message is.
*
* @param {Object} message
* @returns {string} The type of message.
*/
const getMessageType = message => {
const { type } = message.data;
const text = 'text',
quickReplies = 'quickReplies';
if (type.hasOwnProperty(text)) return text;
else if (type.hasOwnProperty(quickReplies)) return quickReplies;
};
/**
* Get the Mongoose's Model of the message's sender. We use
* the sender type to find the Model.
*
* @param {Object} message - The message contains the sender type.
*/
const getSenderModel = message => {
switch (message.sender.type) {
case 'clients':
return 'clients';
case 'users':
return 'users';
default:
return null;
}
};
module.exports = {
getMessageType,
getSenderModel
};
Sisi server saya (menggunakan Nodejs) untuk mendapatkan permintaan menyimpan pesan:
app.post('/api/rooms/:roomId/messages/new', async (req, res) => {
const { roomId } = req.params;
const { sender, timetoken, data } = req.body;
const { uuid, state } = sender;
const { type } = state;
const { lang } = data;
// For more info about message structure, look up Message Schema.
let message = {
room: new ObjectId(roomId),
sender: {
_id: type === 'bot' ? null : new ObjectId(uuid),
type
},
timetoken,
data: {
lang,
type: {}
}
};
// ==========================================
// CONVERT THE MESSAGE
// ==========================================
// Convert the request to be able to save on the database.
switch (getMessageType(req.body)) {
case 'text':
message.data.type.text = data.type.text;
break;
case 'quickReplies':
// Save every quick reply from quickReplies[].
message.data.type.quickReplies = _.map(
data.type.quickReplies,
quickReply => {
const { text, goToBlocks } = quickReply;
return {
text,
goToBlocks
};
}
);
break;
default:
break;
}
// ==========================================
// SAVE THE MESSAGE
// ==========================================
/**
* We save the message on 2 ways:
* - we replace the message type `quickReplies` (if it already exists on database) with the new one.
* - else, we save the new message.
*/
try {
const options = {
// If the quickRepy message is found, we replace the whole document.
overwrite: true,
// If the quickRepy message isn't found, we create it.
upsert: true,
// Update validators validate the update operation against the model's schema.
runValidators: true,
// Return the document already updated.
new: true
};
Message.findOneAndUpdate(
{ room: roomId, 'data.type.quickReplies': { $exists: true } },
message,
options,
async (err, newMessage) => {
if (err) {
throw Error(err);
}
// Populate the new message already saved on the database.
Message.populate(
newMessage,
{
path: 'sender._id',
model: getSenderModel(newMessage)
},
(err, populatedMessage) => {
if (err) {
throw Error(err);
}
res.send(populatedMessage);
}
);
}
);
} catch (err) {
logger.error(
`#API Error on saving a new message on the database of roomId=${roomId}. ${err}`,
{ message: req.body }
);
// Bad Request
res.status(400).send(false);
}
});
TIPS :
Untuk database:
- Setiap pesan adalah dokumen itu sendiri.
- Alih-alih menggunakan
refPath, kami menggunakan util getSenderModelyang digunakan di populate(). Ini karena bot. The sender.typedapat: usersdengan database-nya, clientsdengan database dan bottanpa database. The refPathperlu referensi Model yang benar, jika tidak, Mongooose melempar kesalahan.
sender._iddapat berupa tipe ObjectIduntuk pengguna dan klien, atau nulluntuk bot.
Untuk logika permintaan API:
- Kami mengganti
quickReplypesan (Message DB harus memiliki hanya satu quickReply, tetapi sebanyak yang Anda inginkan). Kami menggunakan findOneAndUpdatealih - alih replaceOneatau findOneAndReplace.
- Kami menjalankan operasi kueri (the
findOneAndUpdate) dan populateoperasi dengan callbackmasing-masing. Hal ini penting jika Anda tidak tahu apakah penggunaan async/await, then(), exec()atau callback(err, document). Untuk info lebih lanjut lihat Populate Doc .
- Kami mengganti pesan balasan cepat dengan
overwriteopsi dan tanpa $setoperator kueri.
- Jika kami tidak menemukan balasan cepat, kami membuat yang baru. Anda harus memberitahu Mongoose ini dengan
upsertopsi.
- Kami hanya mengisi satu kali, untuk pesan yang diganti atau pesan baru yang disimpan.
- Kami kembali ke callback, apa pun pesan yang telah kami simpan dengan
findOneAndUpdatedan untuk populate().
- Di
populate, kami membuat referensi Model dinamis kustom dengan getSenderModel. Kita dapat menggunakan referensi dinamis Mongoose karena sender.typefor bottidak memiliki Model Mongoose. Kami menggunakan Populating Across Database dengan modeldan pathoptins.
Saya telah menghabiskan banyak waktu untuk memecahkan masalah kecil di sana-sini dan saya harap ini akan membantu seseorang! 😃