[SOLVED] Duplicated Data in DB

I have a front end Blaze page with Meteor 3, and a meteor method call to insert data into a collection that no matter what I do I end up with duplicate entries in the database.

I need some sanity checks for sure, but I think I’m doing everything as far as the looping properly here.

Front End:

HTML Template

<template name="taskForm">
    <h4>Tasks</h4>
    <form class="row" style="gap: 1em;">
        <div class="col s12 m6 l4 chips chips-placeholder" id="taskName">
        </div>
        <div class="col s12 m6 l4 input-field">
            <select name="taskUser" id="taskUser" class="taskUser">
                <option value="" disabled selected>Assign to user...</option>
                {{#each taskUsers}}
                    <option value="{{username}}_{{usersId}}">{{username}}</option>
                {{/each}}
            </select>
        </div>
        <div class="col s12 m6 l4 input-field">
            <input type="text" class="datepicker" id="taskDate" />
            <label for="taskDate">Task Date (multiple entries)</label>
            <div class="row">
                {{#each taskDate in taskDates}}
                    <div class="col s6 l3 m4">
                        <span>{{taskDate}}</span>
                    </div>
                {{/each}}
            </div>
        </div>
        <div class="col s12 m6 l6">
            <p>
                <label>
                  <input type="checkbox" id="hideCompletedTasks" />
                  <span>Hide Completed</span>
                </label>
              </p>
        </div>
        <div class="col s12 m6 l6">
                <a class="waves-effect waves-light btn saveTaskMgmt green white-text right">Add</a>
                <!-- <a class="waves-effect waves-light btn testChips blue white-text left" id="testChips">Test Chips</a> -->
        </div>
    </form>
    {{> snackbar}}
</template>

Javascript for page:

'click .saveTaskMgmt' (event) {
        event.preventDefault();
        let elemcc = document.getElementById('taskName');
        let taskNameArr = M.Chips.getInstance(elemcc).chipsData;
        let taskDateArr = Session.get("taskDateArr");
        let taskUser = $("#taskUser").val();
        let taskUserErr = false;
        let taskNameErr = false;
        let taskDateErr = false;
        let userInfo;
        let actDate = [];

        if (taskNameArr == null || taskNameArr == []) {
            taskNameErr = true;
        }

        if (taskDateArr == null || taskDateArr == []) {
            taskDateErr = true;
        } else {
            for (i = 0; i < taskDateArr.length; i++) {
                // console.log(taskDateArr[i]);
                let actDateTask = new Date(taskDateArr[i]);
                actDate.push(actDateTask);
            }
        }

        if (taskUser == null || taskUser == "") {;
            taskUserErr = true;
        } else {
            userInfo = taskUser.split('_');
        }

        if (taskUserErr == false && taskDateErr == false && taskNameErr == false) {
            const addTask = async() => {
                let result = await Meteor.callAsync("add.task", taskNameArr, userInfo[0], userInfo[1], taskDateArr, actDate);
                if (!result) {
                    console.log("    ERROR adding the new task.");
                } else {
                    console.log("    SUCCESS adding the new task.");
                    Session.set("taskDateArr", []);
                    $("#taskDate").val("");
                    $("#taskUser").val("");
                    $('select').formSelect();
                }
            }
            addTask();
        } else {
            showSnackbar("ERROR: Missing Required Fields!", "red");
        }

Back End:

Method Call:

'add.myTask' (taskName, taskDate, actDate) {
        check(taskName, String);
        check(taskDate, String);
        check(actDate, Date);

        if (!this.userId) {
            throw new Meteor.Error('You are not allowed to add tasks. Make sure you are logged in with valid user credentials.');
        }

        const uInfo = async() => {
            let userInfo = await Meteor.users.findOneAsync({ _id: this.userId });
            if (!userInfo) {
                console.log("No matching user info found.")
            } else {
                try {
                    await TaskItems.insertAsync({
                        taskName: taskName,
                        taskDate: taskDate,
                        actualDate: actDate,
                        assignedTo: userInfo.profile.fullname,
                        assignedToId: this.userId,
                        isComplete: false,
                        completedOn: null,
                        assignedOn: new Date(),
                        assignedBy: this.userId,
                    });
                } catch(error) {
                    console.log("    ERROR adding tasks " + error.message);
                }
            }
        }
        uInfo();

If I use this to enter 2 tasks, ‘trash’ and ‘mow lawn’, on 2 dates, then I see this in the log output:

I20250721-16:38:17.961(-5)? 'trash'
I20250721-16:38:17.973(-5)? 'Jul 22, 2025'
I20250721-16:38:17.973(-5)? 2025-07-22T05:00:00.000Z
I20250721-16:38:17.973(-5)? ---------------------------------
I20250721-16:38:17.974(-5)? 'trash'
I20250721-16:38:17.974(-5)? 'Jul 23, 2025'
I20250721-16:38:17.974(-5)? 2025-07-23T05:00:00.000Z
I20250721-16:38:17.974(-5)? ---------------------------------
I20250721-16:38:17.975(-5)? 'mow lawn'
I20250721-16:38:17.975(-5)? 'Jul 22, 2025'
I20250721-16:38:17.975(-5)? 2025-07-22T05:00:00.000Z
I20250721-16:38:17.975(-5)? ---------------------------------
I20250721-16:38:17.977(-5)? 'mow lawn'
I20250721-16:38:17.977(-5)? 'Jul 23, 2025'
I20250721-16:38:17.977(-5)? 2025-07-23T05:00:00.000Z
I20250721-16:38:17.977(-5)? ---------------------------------

but I end up with this from mongoshellL

meteor [direct: primary] meteor> db.taskitems.find({}).count();
8

I’m sure I’ve got something odd happening, here, but I have not idea what it is. Any help is greatly appreciated.

You can check about debounce in javascript. This is normal in events triggered from the client.

ok, I’ll look into it. I’ve never had this happen before. Is this specifically because of the async await stuff we are using now?

Your back-end method doesn’t look right.

it should look like this:

async 'add.myTask' (taskName, taskDate, actDate) {
	check(taskName, String);
	check(taskDate, String);
	check(actDate, Date);

	if (!this.userId) {
		throw new Meteor.Error('You are not allowed to add tasks. Make sure you are logged in with valid user credentials.');
	}

	let userInfo = await Meteor.users.findOneAsync({ _id: this.userId });
	if (!userInfo) {
		console.log("No matching user info found.")
	} else {
		try {
			await TaskItems.insertAsync({
				taskName: taskName,
				taskDate: taskDate,
				actualDate: actDate,
				assignedTo: userInfo.profile.fullname,
				assignedToId: this.userId,
				isComplete: false,
				completedOn: null,
				assignedOn: new Date(),
				assignedBy: this.userId,
			});
		} catch(error) {
			console.log("    ERROR adding tasks " + error.message);
		}
	}

I don’t need the ‘async’ in order to use the ‘await’ for these? Why the difference here?

If I comment out the ‘async’ and the function call to it, I get this in the terminal:

     55|         While building for os.linux.x86_64:
   imports/api/tasks.js:58:27: /home/brian/Developer/get_my/imports/api/tasks.js:
   Unexpected reserved word 'await'. (58:27)
   
     56 |
    57 |         // const uInfo = async() => {
   > 58 |             let userInfo =
   await Meteor.users.findOneAsync({
   _id: this.userId });
       |                            ^
    59 |             if (!userInfo) {
    60 |                 console.log("No matching user info
   found.")
    61 |             } else {
   
=> Your application has errors. Waiting for file change.

The difference is that instead of creating async function within your method and then calling it, the async def is moved to the method callback itself here:

By moving this here, and converting the callback to a async function the return from the callback becomes a promise that can be awaited. This ensures that the callback doesn’t complete before all of the async code inside it also completes.

Using the code that you currently have, the callback executes, creates the async function, puts it on the microtask queue and returns. This means that the method callback cannot be awaited and Meteor just executes the next method callback from that user if there are any methods that were called. So if the method was called twice in succession, the first call executes, dumps the uInfo call onto the queue and does the same for the next one.

I’m not going to say that this is the exact problem you are seeing, but the code @minhna has provided is a much better pattern and your current code it could definitely lead to unforeseen issues.

1 Like

Thank you. You explained it much better than I can.

1 Like

You give yourself far too little credit with that statement.

1 Like

You all are always the best. I truly appreciate it, that did it. Thank yo so much.

1 Like