Mongoose keep duplicate elements - javascript

I have a function that create guild entry for DiscordJS, but when the script start and also if the function is called multiple times, it create around 400 duplicate documents, it create by ID and the ID is unique, so it's not normal
My schema structure only have a ID type String and unique is true
client.createGuild = async guild => {
const exist = await Guild.findOne({ id: guild.id });
if(!exist) {
await Guild.create({ id: guild.id }); // new Guild().save() keep duplicate too
}
}
It look like the if statement doesn't exist

const Schema = mongoose.Schema;
const FooSchema = new Schema({
id: { type: String, index: true, unique: true }
});
const Foo = mongoose.model('Foo', FooSchema);
Foo.createIndexes();
If collection already exists. Create index manually to the collection via atlas or cmd.

You can combine getData and createData functions to one. Here is the example:
const mongoose = require('mongoose');
async function getData(Guild, guild) {
if (!mongoose.connection.readyState) await mongoose.connect('MONGO_URL'); // In case you haven't connect to database
const data = await Guild.findOne({ id: guild.id }); // get data from database
if (!data) {
return new Guild({
id: guild.id,
}); // If no data exists for the guild, return new model
}
return data; // If the data already exists, return that
}
Now if you want to get data from mongodb you just call the function. It automatically create and save a new one if there is not.
Comment if you still have any problem or you have got what you need.
Make sure to call the function with await or it won't return the data.

Related

MongoDB updateOne not able to update document when referring an ID as filter

I'm trying to update a property value of a single document by sending a request to my NextJs API via fetch.
// Update items in state when the pending time in queue has passed, set allowed: true
items.map((item) => {
const itemDate = new Date(item.added)
const timeDiff = currentDate.getTime() - itemDate.getTime()
const dateDiff = timeDiff / (1000 * 3600 * 24)
if (dateDiff >= 7) {
const updateItem = async () => {
try {
// Data to update
const updatedItem = {
_id: item._id,
name: item.name,
price: item.price,
allowed: true
}
console.log(updatedItem)
await fetch ('/api/impulses', {
method: 'PATCH',
body: JSON.stringify(updatedItem)
})
} catch (error) {
alert('Failed to update items status')
}
}
updateItem()
}
})
API receives the data object as a whole and I am able to parse every piece of data I need for updating the MongoDb document from the req.body. However, when trying to use the item's _id (which is generated by MongoDb and values as _id: ObjectId('xx1234567890xx')) to filter the document I need to update, it seems to treat the ID differently.
I've tried to mess around with the format, forcing the object that gets sent to the API to include just the things I want to be updating (and the _id, of course) but still...
const jsonData = JSON.parse(req.body)
const { _id } = jsonData
// Fields to update
const { name, price, allowed } = jsonData
const data = {
name,
price,
allowed
}
const filter = {
_id: _id
}
const update = {
$set: data
}
const options = {
upsert: false
}
console.log("_id: ", filter) // returns { _id: 'the-correct-id-of-this-document' }
And finally, updating thedb.collection and returning responses:
await db.collection('impulses').updateOne(filter, update, options)
return res.json({
message: 'Impulse updated successfully',
success: true
})
So, as the _id clearly matches the document's id, I cannot figure out why it doesn't get updated? To confirm that this isn't an issue with database user privileges, if I set upsert: true in options, this creates a new document with the same _id and the updated data the request included...
Only difference to the other documents created through a submit form is that the id is in the following format: _id: 'xx1234567890xx' - so, comparing that to an ID with the ObjectId on front, it doesn't cause a conflict but I really don't get this behavior... After noticing this, I've also tried to include the 'ObjectId' in the ID reference in various ways, but it seemed like initiating a new ObjectId did exactly that - generate a new object ID which no longer referenced the original document.
Any ideas?
You compare an ObjectId object from _id with a string, this does not work.
Create proper filter object, e.g.
const filter = { _id: ObjectId(_id) }
or the other way around:
const filter = { $expr: {$eq: [{$toString: "$_id"}, _id] } }
but this will prevent to use the index on _id, so the first solution should be preferred.

Firebase: Add a Additional Collection to a Document Unhandled Promise Rejection

I currently have a Collection | Document | Collection Firestore.
I want to search for a specific collection within the document and if the user ID matches, then update. If the user ID is not in the collection, then I want to add a new collection.
The collection update aspect works, but getting a Promise Rejection when adding to the collection via .set().
if (!query.empty) {
console.log('event leaderboard exists in db');
for (let i in leaderboard) {
const result = leaderboard[i].data();
for (let y in result) {
const userLeaderboard = result[y];
if (userLeaderboard.uid === currentUser.uid) {
// User exists in record and update score
return query.docs[i].ref.update({
score: increaseBy,
});
} else {
// User does not exist and need to add to record
addUserToLeaderboard();
}
}
}
...
const addUserToLeaderboard = async() => {
let userLeaderboard = {
uid: currentUser.uid,
score: currentTrivia.points,
banned: false,
};
const leaderboardRef = db.collection('leaderboard').where(firebase.firestore.FieldPath.documentId(), '==', eventId);
await leaderboardRef.set(userLeaderboard, { merge: true });
}
You can't call set on a query.
If you want to update the one document with the given ID, use:
const leaderboardRef = db.collection('leaderboard').doc(eventId);
await leaderboardRef.set(userLeaderboard, { merge: true });
If you want to update (potentially multiple) items matching a query, you'll need to execute the query, loop over the results, and update each document in turn. But that' doesn't seem to be needed here.

Mongoose, instant destructuring to a database document?

when fetching a document from the database, I want to destructure fields from it in one line, other ORMs such as TypeORM offer this ability out of the box, but I couldn't manage to do the same with Mongoose.
example:
// working TypeORM example
const { id, name, email } = await this.userRepository.findOne({ handle: 'JohnDoe' });
// the above line is achieved with mongoose with 2 additional steps:
const doc = await this.userModel.findOne({ handle: 'JohnDoe' });
const { id } = doc;
const { name, email } = doc.toObject();
How to improve the mongoose example above, thanks!

Update array inside of Mongo document doesn't work

I have a user's collection, each user has a subscription array of objects. I want to add another subscription to that array. I'm getting the new subscription, updating it with findByIdAndUpdate, but it doesn't add the new subscription, however it shows that the document was updated. I tried several approaches but nothing worked well.
Here is the last approach:
...
const { user_id } = req.params;
const subscription = req.body; // Getting subscription
const user = await UserModel.findById(user_id).lean().exec(); // Getting user by id
const { push_subscriptions } = user; // Getting subscribtions with destructuring
const updated_subs = [...push_subscriptions, subscription];
// Getting user another time and updating the push_subscriptions array
const updated_user = await UserModel.findByIdAndUpdate(user_id,
{push_subscriptions: updated_subs},
{ new: true }
).exec();
...
Here are the logs of request body and params
// body
{
endpoint: 'https://fcm.googleapis.com/fcm/send/cQ6wlRJ8t-s:APA91bEjqdLMzQLsroJ7zHzdjrzoshdPD8IJy_iIeRa8qV_Yjt6N1jeMUtyMq73wSn9JJT-4WXr_8uwHXttj-XFxHPCPAOqgN7zALsmf_BeIRZowRBTRHf9YH8v3AlcaZXWAIQ0qJNdn',
expirationTime: null,
keys: {
p256dh: 'BBPC5h1QnBMPKMfPacgJu_2RFT7LAejyINh3CvP4pamkrlERr06YpRlSb7RbTUOn6MYW4adG93KfdEWXz68F9iQ',
auth: 'Zl3iaOdBvihXG2QVOb26IQ'
}
}
//params
{ user_id: '5fedc679f414663c693cf549' }
User schema, push_subscriptions part:
push_subscriptions: {
type: Array,
},
Your query looks good, you can do single query using $push instead of doing manual process,
const { user_id } = req.params;
const subscription = req.body;
const updated_user = await UserModel.findByIdAndUpdate(user_id,
{
$push: {
push_subscriptions: subscription
},
{ new: true }
).exec();

Multiple MongoDB queries in a Javascript function?

How can I execute the following queries together in a single javascript function for mongoDB?
//find the reviews from the reviews collection
var proRev = db.reviews.find({productID: "123"}).toArray();
//update the products collection
db.products.update({productID : "123"},{$push:{Reviews:proRev}},{multi:true});
//remove the reviews from the reviews collection
db.reviews.remove({productID: "123"});
The function would be based on finding the reviews for productID "123" from a reviews collection, and inserting them as an array, in a new field for productID "123" found in the products collection.
Rather than executing the queries seperate, I would like them to execute in a single function - I'm a javascript noob so sorry if this is a stupid question.
Thanks
Use promises.
Example:
const MongoClient = require('mongodb').MongoClient;
const url = 'mongodb://localhost:27017';
const dbName = 'myproject';
(async function() {
let client;
try {
client = await MongoClient.connect(url);
console.log("Connected correctly to server");
const db = client.db(dbName);
const [res1, res2] = await Promise.all([
db.collection('inserts').findOne({
foo: "bar"
}),
db.collection('inserts').findOne({
bar: "foo"
})
]);
} catch (err) {
console.log(err.stack);
}
// Close connection
client.close();
})();
If you want to do it in one operation within MongoDB, try using findOneAndUpdate

Categories