Sorun yaşayan populate
ve bunu yapmak isteyen biri için:
- basit metin ve hızlı yanıtlarla (baloncuklar) sohbet edin
- Sohbet için 4 veritabanı koleksiyonları:
clients
, users
, rooms
, messasges
.
- 3 tür gönderici için aynı mesaj DB yapısı: bot, kullanıcılar ve istemciler
refPath
veya dinamik referans
populate
ile path
ve model
seçenekler
- Kullanım
findOneAndReplace
/ replaceOne
ile$exists
- getirilen belge yoksa yeni bir belge oluşturun
BAĞLAM
Hedef
- Veritabanına yeni bir basit metin mesajı kaydedin ve bunu kullanıcı veya müşteri verileriyle doldurun (2 farklı model).
- Veritabanına yeni bir QuickReplies mesajı kaydedin ve bunu kullanıcı veya müşteri verileriyle doldurun.
- Her mesaj kendi gönderen türünü kaydedin:
clients
, users
&bot
.
- Yalnızca gönderene sahip olan
clients
veya users
onun Mongoose Modelleri olan iletileri doldurun. _sender tipi istemci modelleri, clients
kullanıcı içindir users
.
Mesaj şeması :
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);
ÇÖZÜM
Sunucu tarafı API isteğim
Benim kodum
chatUtils.js
Kaydetmek istediğiniz mesajın türünü almak için yardımcı program işlevi ( dosyada):
/**
* 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
};
İletiyi kaydetme isteğini almak için sunucu tarafım (Nodejs kullanarak):
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);
}
});
İPUÇLARI :
Veritabanı için:
- Her mesaj bir belgenin kendisidir.
- Bunun yerine kullanmanın
refPath
, biz util kullanmak getSenderModel
kullanılır populate()
. Bunun nedeni bot. sender.type
Olabilir: users
Onun veritabanı ile, clients
onun veritabanı ile ve bot
bir veritabanı olmadan. refPath
Değilse, Mongooose hata atmak, gerçek Modeli referansı gerekiyor.
sender._id
ObjectId
kullanıcılar ve müşteriler null
için veya bot için yazılabilir .
API istek mantığı için:
quickReply
Mesajı değiştiririz (Mesaj DB'nin yalnızca bir hızlı Yanıt olması gerekir, ancak istediğiniz kadar basit metin mesajı gerekir). Veya findOneAndUpdate
yerine kullanıyoruz .replaceOne
findOneAndReplace
- Sorgu işlemini (the
findOneAndUpdate
) ve populate
işlemi callback
her biri ile gerçekleştiriyoruz. Eğer kullanım eğer bilmiyorsanız bu önemlidir async/await
, then()
, exec()
veya callback(err, document)
. Daha fazla bilgi için Populate Doc'a bakın .
- Hızlı yanıt mesajını
overwrite
seçenekle ve $set
sorgu operatörü olmadan değiştiriyoruz .
- Hızlı cevabı bulamazsak yeni bir tane yaratırız. Bunu Mongoose'a
upsert
seçenekle söylemelisin .
- Değiştirilen mesaj veya yeni kaydedilmiş mesaj için yalnızca bir kez doldururuz.
- İle
findOneAndUpdate
ve için kaydettiğimiz mesaj ne olursa olsun geri aramalara geri dönüyoruz populate()
.
- Olarak
populate
biz ile özel bir dinamik model referans oluşturmak getSenderModel
. Çünkü Gelincik dinamik başvuru kullanabilirsiniz sender.type
için bot
herhangi Gelincik Modeli değildir sahiptir. Biz kullanmak Veritabanı karşısında doldurulmaya ile model
ve path
optins.
Burada ve orada küçük sorunları çözmek için çok zaman harcadım ve umarım bu birilerine yardımcı olur! 😃