Discord.js/Mongodb How to update all database values - mongodb

I am currently creating an economy bot for Discord, and i have a problem i don't know how to solve:
All users have a salary, that will be set with a command. I want to create a command that can update all users account with the set salary amount.
Instead of having to ping a specific user, how could i make it that the command would update values of all found users in the MongoDB Database?
Here is current code:
const profileModel = require("../models/profileSchema");
module.exports = {
name: 'pay',
aliases: [],
permissions: ["ADMINISTRATOR"],
description: "pay users their salary",
async execute(message, args, cmd, client, discord, profileData) {
const amount = profileData.pay;
const target = message.mentions.users.first();
try{
await profileModel.findOneAndUpdate({
userID: target.id,
}, {
$inc: {
bank: amount,
},
}
);
return message.channel.send(`Users have been paid.`);
} catch(err) {
console.log(err);
}
},
};
As you can see, currently its waiting for the user to ping a user. But i would want it to just update all found users inside the Database without needing to specify who it is.
I would really appereciate help!

Mongo has the method updateMany, docs found here, which updates all documents if the query is set to an empty object. So, just try:
await profileModel.updateMany({}, {
$inc: {
bank: amount,
},
}
);

Related

MongoDB Atlas triggers - access different collection

I have a trigger on new documents in collection A, in which I want to get a related record from the users collections.
I (think) I followed the documentation to the "t", but both the collection itself comes out empty and the actual user I'm trying to fetch. And ideas what I'm doing wrong?
exports = async function trigger(changeEvent) {
const toolRecord = changeEvent.fullDocument;
const usersCollection = await context.services
.get("Cluster0")
.db("mind-tools")
.collection("users");
const user = await usersCollection.find({ _id: toolRecord.userId });
const users = await usersCollection.find({});
const text = [
"New tool record - " + toolRecord._id,
toolRecord.toolKey,
"users",
JSON.stringify(usersCollection),
JSON.stringify(users[0]),
"user",
toolRecord.userId,
JSON.stringify(user),
user.name,
user.email,
]
.filter(Boolean)
.join("\n");
}
Try to use findOne instead of find for the user.
Replace:
const user = await usersCollection.find({ _id: toolRecord.userId });
with:
const user = await usersCollection.findOne({ _id: toolRecord.userId });
Is it possible to console.log() different variables in your script to see what value they got in run time?
Also in the example provided in Atlas tutorial, the first line is
exports = async function (changeEvent) { ...
Without the keyword "trigger"

How to pass data for sync function using watermelondb

Good day everyone, I am working with watermelondb and I have the code below, but I don't know how to actually use it. I am new in watermelondb and I don't know how to pass data as props to the pullChanges and pushChanges objects. How do I pass necessary data like changes and lastPulledAt from the database into the sync function when I call it. And I need more explanation on the migrationsEnabledAtVersion: 1 too. Thanks in advance for your gracious answers.
import { synchronize } from '#nozbe/watermelondb/sync'
async function mySync() {
await synchronize({
database,
pullChanges: async ({ lastPulledAt, schemaVersion, migration }) => {
const urlParams = `last_pulled_at=${lastPulledAt}&schema_version=${schemaVersion}&migration=${encodeURIComponent(JSON.stringify(migration))}`
const response = await fetch(`https://my.backend/sync?${urlParams}`)
if (!response.ok) {
throw new Error(await response.text())
}
const { changes, timestamp } = await response.json()
return { changes, timestamp }
},
pushChanges: async ({ changes, lastPulledAt }) => {
const response = await fetch(`https://my.backend/sync?last_pulled_at=${lastPulledAt}`, {
method: 'POST',
body: JSON.stringify(changes)
})
if (!response.ok) {
throw new Error(await response.text())
}
},
migrationsEnabledAtVersion: 1,
})
}
Watermelondb's documentation is terrible and its link to typescript even worse.
I spent almost a week to get 100% synchronization with a simple table, now I'm having the same problems to solve the synchronization with associations.
Well, the object you need to return in pullChanges is of the following form:
return {
changes: {
//person is the name of the table in the models
person: {
created: [
{
// in created you need to send null in the id, if you don't send the id it doesn't work
id: null,
// other fields of your schema, not model
}
],
updated: [
{
// the fields of your schema, not model
}
],
deleted: [
// is a string[] consisting of the watermelondb id of the records that were deleted in the remote database
],
}
},
timestamp: new Date().getTime() / 1000
}
In my case, the remote database is not a watermelondb, it's a mySQL, and I don't have an endpoint in my API that returns everything in the watermelon format. For each table I do a search with deletedAt, updatedAt or createdAt > lastPulledAt and do the necessary filtering and preparations so that the data from the remote database is in the schema format of the local database.
In pushChanges I do the reverse data preparation process by calling the appropriate creation, update or deletion endpoints for each of the tables.
It's costly and annoying to do, but in the end it works fine, the biggest problem is watermelon's documentation which is terrible.

Updating current user's email address in Meteor

I'm having a problem updating the current user's email address in Meteor. The problem code is here (it's all client code):
var id = Meteor.userId();
if (firstName) {
Meteor.users.update(
{ _id: id },
{ $set: { "profile.firstName": firstName }}
)};
if (lastName) {
Meteor.users.update(
{ _id: id },
{ $set: { "profile.lastName": lastName }}
)};
var oldEmail = Meteor.user().emails[0].address;
if (newEmail) {
Meteor.users.update(
{ _id: id, 'emails.0.address': oldEmail },
{ $set: { 'emails.0.address': newEmail }}
)};
The first two lines work fine (user can update their first and last names), but the last update fails with the following error showing in the console:
"errorClass {isClientSafe: true, error: 403, reason: "Not permitted. Untrusted code may only update documents by ID."
I don't understand the error, because I AM updating by ID--or at least I think I am.
Also: if I remove the reference to the old email, I get a simple "Update failed. Access denied" error in the console instead of the above-mentioned error.
Is there a way to fix this with client-side code only?
(I realize I'll also need to reset the "verified" key back to false, but that's a different issue I guess)
Do not edit the emails array directly. The Accounts package has utility functions for this use case, see Accounts.addEmail and Accounts.removeEmail.
First you will need to invoke a Method since these functions must be performed on the server.
Client js:
if (newEmail) {
Meteor.call('updateEmail', newEmail, err => {
if (err) console.log(`Error updating email address: {err}`);
});
}
server:
Meteor.methods({
updateEmail(newAddress) {
const userId = this.userId;
if (userId) {
const currentEmail = Meteor.users.findOne(userId).emails[0].address;
Accounts.addEmail(userId, newAddress);
Accounts.removeEmail(userId, currentEmail)
}
return;
}
});
You should also validate in your method that the new email address is a string that has an email address pattern.

Meteor: Publish using users profile properties rather than ID

I'm currently creating an app that will be used by multiple companies.
Each user has the following profile:
username: johnDoe
emails: [{address: "some#email.com", verified: true}],
profile: {
name: "John Doe",
companyId: "1234"
}
I then have a collection (called Companies) of company objects that contain configuration info, templates etc specific to that company.
{
id: "1234",
configuration: {},
templates: []
}
In order to isolate each companies data I want to only publish data that matches the users profile companyId to the companies id.
if (Meteor.isServer) {
// collection to store all customer accounts
Companies = new Mongo.Collection('Companies');
// publish collection
Meteor.publish("Company", function () {
return Companies.find({id: Meteor.user().profile.companyId});
})
}
This currently works if I hardcode the clinic Id
// publish collection
Meteor.publish("Company", function () {
return Companies.find({id: "1234");
})
But returns an empty cursor with the Meteor.user().profile.companyId.
This means that the issue is either that I'm using the wrong function or more probably, the publish is happening before the user().profile.companyId can run.
Anybody know what I'm doing wrong? and do you have any advice on what to read up about so that I have an understanding of this moving forwards?
Thanks
Try doing an explicit findOne() in your publish function:
// publish collection
Meteor.publish("Company", function () {
var user = Meteor.users.findOne({_id: this.userId});
if(user && user.profile && user.profile.companyId) {
return Companies.find({id: user.profile.companyId});
} else {
console.log(user);
return this.ready();
}
});

Accessing services field of Meteor.users

When I query Meteor.users I do not receive the services field or any other custom fields I have created outside of profile. Why is it that I only receive _id and profile on the client and how can I receive the entire Meteor.users object?
Thanks.
From the DOcs
By default, the current user's username, emails and profile are published to the client. You can publish additional fields for the current user with:
As said above If you want other fields you need to publish them
// server
Meteor.publish("userData", function () {
if (this.userId) {
return Meteor.users.find({_id: this.userId},
{fields: {'services': 1, 'others': 1}});
} else {
this.ready();
}
});
// client
Meteor.subscribe("userData");
The above answer does work, but it means you have to subscribe to said data, which you should do if you are getting data from users other than the currently logged in one.
But if all you care about is the logged in user's data, then you can instead use a null publication to get the data without subscribing.
On the server do,
Meteor.publish(null, function () {
if (! this.userId) {
return null;
}
return Meteor.users.find(this.userId, {
fields: {
services: 1,
profile: 1,
roles: 1,
username: 1,
},
});
});
And this is actually what the accounts package does under the hood