0

I'm having issues adding an array of objects to mongodb. The problem is related to when I get the posts ngOnInit() and there is an entry for _id like this before I start adding anything to inviteGroup

enter image description here

If I add this.inviteGroup = [] to get rid of _id first entry, then I can successfully add to the database my invite like in this image. Is there a way to not have that _id that's related to my mongoose schema? but naturally the this.inviteGroup = [] makes it so I can have only one entry at a time since it erases everything on page load. How can I make that _id entry not there anymore so that when I do a .push() it doesn't cause a page reload because it throws off the .push(). I want to have multiple entries in db for each invite. Is it my mongoose model that's the issue? I appreciate any help!

enter image description here

mongoose schema definition

 inviteGroup: {
    bidderId: { type: String, lowercase: true, trim: true },
    username: { type: String, lowercase: true, trim: true }
  }

app.js

app.patch("/api/listings/:id", (req, res) => {
  console.log("INVITE GRdddOUP IS");
  console.log(req.body);
  console.log(req.body[0].biddingUserId);
  let invites;
  if (req.body[0].biddingUserId) {
    invites = req.body;
    console.log("INVITE IS");
  }
  console.log(invites);
  if (invites) {
    console.log("INVITE GROUP IS");
    console.log(req.params.id);
    Post.findByIdAndUpdate(
      { _id: req.params.id },
      {
        inviteGroup: invites
      },
      function(err, docs) {
        if (err) {
          console.log(err);
          res.json(err);
        } else {
          return true;
          console.log(docs);
        }
      }
    );

component.ts

import {
  Component,
  OnInit,
  ViewChild,
  OnDestroy,
  AfterViewInit
} from "@angular/core";
import { Router } from "@angular/router";
import {
  MatTableDataSource,
  MatPaginator,
  MatSort,
  MatDialog
} from "@angular/material";
import { NgForm, FormControl } from "@angular/forms";
import { SubmitListingService } from "../submit-listing/submit-auction.service";
import { BidderInvite } from "./bidder-invite.model";
import { Observable, Subject } from "rxjs";
import { startWith, map, takeUntil } from "rxjs/operators";
import { Page } from "ngx-pagination/dist/pagination-controls.directive";
import { BidderInviteRetrieved } from "./bidder-invite-retrieved";
@Component({
  selector: "app-private-auction-invite",
  templateUrl: "./private-auction-invite.component.html",
  styleUrls: ["./private-auction-invite.component.css"]
})
export class PrivateAuctionInviteComponent
  implements OnInit, AfterViewInit, OnDestroy {
  allMyPeopleAreInvited: boolean;
  auctionId: string;
  dataSource: MatTableDataSource<any> = new MatTableDataSource();
  timeout: any = null;
  posts: BidderInviteRetrieved[];
  artistId: string;
  bidderId: string;
  inviteGroup: BidderInvite[] = [];
  test: any[] = [];
  value: string;
  usernameFound: string;
  userSearched: string;
  invites: BidderInvite[] = [];
  destroy = new Subject();
  inviteName: string;
  filteredOptions: Observable<string[]>;
  myControl = new FormControl();
  selectedValue: string;

  url: string;
  displayedColumnsInvites: string[] = ["User", "revokeInvite"];
  options: string[] = [];

  @ViewChild(MatSort, { static: false }) set sort(sort: MatSort) {
    this.dataSource.sort = sort;
  }

  @ViewChild(MatPaginator, { static: false }) set paginator(
    paginator: MatPaginator
  ) {
    this.dataSource.paginator = paginator;
  }

  constructor(
    private router: Router,
    private submitListingService: SubmitListingService
  ) {}

  ngOnInit() {
    this.inviteGroup = [];
    this.dataSource.paginator = this.paginator;
    this.dataSource.sort = this.sort;
    this.allMyPeopleAreInvited = false;
    this.url = this.router.url;
    const value = this.router.url.split("/");

    this.auctionId = value[2];
    this.artistId = value[3];


    this.submitListingService
      .getPrivateAuctionInviteList(this.auctionId)
      .pipe(takeUntil(this.destroy))
      .subscribe(res => {
        this.inviteGroup = res.posts;
        console.log("res");
        console.log(res);
        console.log(this.inviteGroup);

        if (this.inviteGroup["_id"].length > 2) {
          this.inviteGroup = [];
          console.log(this.inviteGroup);
        }
      });

    this.filteredOptions = this.myControl.valueChanges.pipe(
      startWith(""),
      map(value => this._filter(value))
    );
  }
  ngAfterViewInit() {
    this.dataSource.paginator = this.paginator;
    this.dataSource.sort = this.sort;

    this.dataSource = new MatTableDataSource(this.inviteGroup);

    this.dataSource.data = this.inviteGroup;
  }

  sendInvite(form: NgForm) {
    if (form.invalid) {
      return;
    }

    let counter: number;
    counter = 0;
    console.log("USER " + this.value);
    console.log("POST LEGNTH: " + this.posts.length);
    for (let i = 0; i < this.posts.length; i++) {
      counter = counter++;
      console.log("post");
      console.log(form.value.username);

      let user = this.posts[i].username.trim().toLowerCase();
      let enteredUser = form.value.username.trim().toLowerCase();
      console.log("COUNTER LOOP NUMBER: " + counter);


      if (enteredUser === user) {
        this.bidderId = this.posts[i].id;
        console.log(this.inviteGroup);

        let invites = this.inviteGroup;
        console.log("INVITE LENGTH =  " + this.inviteGroup.length);
        console.log(invites.indexOf);
        this.inviteGroup.push({
          biddingUserId: this.bidderId,
          username: this.posts[i].username
        });

        console.log(this.inviteGroup);
        console.log("invite group");
        console.log(this.inviteGroup);
        //this.posts = [];

        this.dataSource.data = this.inviteGroup;
        console.log("invite group");
      }
    }

    console.log("BIDDER ID " + this.bidderId);
    if (this.bidderId === null || this.bidderId === undefined) {
      console.log("SOMETHING WENT WRONG");
    }
    console.log("made it to next section");

    let invites = this.inviteGroup;
    console.log("invites[0].username");


    console.log("filtering....");

    invites = invites.filter((obj, pos, arr) => {
      return (
        arr.map(mapObj => mapObj["bidderId"]).indexOf(obj["bidderId"]) === pos
      );
    });

    console.log("invites");
    console.log(invites);
    this.submitListingService
      .sendPrivateAuctionInvite(this.auctionId, invites)
      .pipe(takeUntil(this.destroy))
      .subscribe(res => {
        console.log("res");
        console.log(res);
      });
  }

  private onKeySearch(event: any) {
    console.log("EVENT IS ");
    console.log(event);

    clearTimeout(this.timeout);
    var $this = this;
    this.timeout = setTimeout(function() {
      if (event.keyCode !== 13) {
        $this.executeListing(event.target.value);
      }
    }, 1000);
  }

  private executeListing(bidderName: string) {
    console.log("BIDDERNAME");
    console.log(bidderName);
    if (bidderName === "[Object object]") {
      return;
    }
    if (bidderName.length < 4) {
      return;
    }
    if (bidderName.length > 3) {
      this.submitListingService
        .getUserIdAutoComplete(bidderName)
        .pipe(takeUntil(this.destroy))
        .subscribe(res => {
          console.log("res");
          console.log(res);
          this.posts = res.posts;
          console.log(this.posts);

          //   this.artists = res.posts;
        });
    }
  }
  private _filter(value: string): string[] {
    const filterValue = value.toLowerCase();

    return this.options.filter(
      option => option.toLowerCase().indexOf(filterValue) === 0
    );
    console.log("OPTION IS " + filterValue);
  }
  storeUserPrivaeAuctionInvite(user: Page) {
    console.log("USER VALUE I S" + user);
  }

  ngOnDestroy() {
    this.destroy.next();
    this.destroy.complete();
  }
}

angular service

 sendPrivateAuctionInvite(id: string, inviteGroup1: BidderInvite[]) {

   // console.log(inviteGroup1);
    return this.http.patch(
      `http://localhost:3000/api/listings/${id}/`,
      inviteGroup1
    );
  }

BidderInvite model

export interface BidderInvite {
  biddingUserId: string;
  username: string;
}

3 Answers 3

1
+100

Is your schema definition supposed to be:

 inviteGroup: {
    type: [inviteSchema]
    default: undefined //if you want to unset [] 
 }

 invite: {
    bidderId: { type: String, lowercase: true, trim: true },
    username: { type: String, lowercase: true, trim: true }
  }

(See https://mongoosejs.com/docs/schematypes.html#arrays)

Try caching to prevent a reload. (See https://github.com/isaacs/node-lru-cache) and How to stop MongoDB from reloading data every time I refresh a page?

Try projection to exclude _id in a query output with _id: 0. See https://docs.mongodb.com/v3.2/tutorial/project-fields-from-query-results/#return-all-but-the-excluded-field

Sign up to request clarification or add additional context in comments.

1 Comment

projection fixed my problem. Thanks!
0

Try this. Hope it will help you.

    Post.findByIdAndUpdate(
          { _id: req.params.id },
          {
            inviteGroup: invites
          },
          {select: {_id: 0}}, // sets the document fields to return
          function(err, docs) {
            if (err) {
              console.log(err);
              res.json(err);
            } else {
              return true;
              console.log(docs);
            }
          }
        );

1 Comment

That will only work if I don't comment out this.inviteGroup = []; because if it was commented out then the ._id in first JSON console image would be causing a page reload when I .push() into JSON object. But then that leads us to still only having one entry at a time in mongodb since this.inviteGroup = [] is clearing results on page load every time so I can't append next invite to object. It will be pushing into an empty object everytime instead of appending.
0

If I understood your question right, the problem is related to the lack of operator at the update method.

When you use something like:

Post.findByIdAndUpdate(
  { _id: req.params.id },
  {
    inviteGroup: invites // <-- Update statement
  },
  function(err, docs) {
    //...
  }
);

It will replace the full value of the inviteGroup field.

In order to add an item to an existent array on the database, you will need to use $push or $addToSet operator, along with $each operator.

The $push and $addToSet operators, only add/append one item per time, so the use of $each is necessary to interact with every item present on the invites array. In the following examples, I will include that because I believe is what you will need. But please, take the time to read the linked documentation of every operator so you can find more samples.

The $push operator appends a specified value to an array, making no extra verification if the value that is been added already exists on the field or not. As:

//document on mongodb, before the update
// { _id : "1", inviteGroup : [] }


//Invites from the request
// invites = [ { bidderId:"5e2350c7f88cfb331c4f67de", username:"artist1"} ];

//update method
Post.findByIdAndUpdate(
  { _id: req.params.id }, //req.params.id = "1"
  { $push : { inviteGroup: { $each : invites } } },
  function(err, docs) {
    //...
  }
);

//document on mongodb, after the update
/*
{
  _id : "1",
  inviteGroup : [ { bidderId:"5e2350c7f88cfb331c4f67de", username:"artist1"} ]
}
*/

If you call the update method again with the same values:

Post.findByIdAndUpdate(
  { _id: req.params.id }, //req.params.id = "1"
  { $push : { inviteGroup: { $each : invites } } },
  function(err, docs) { }
);

// the end document will be like:
/*
{
  _id : "1",
  inviteGroup : [
    { bidderId:"5e2350c7f88cfb331c4f67de", username:"artist1"},
    { bidderId:"5e2350c7f88cfb331c4f67de", username:"artist1"}
  ]
}
*/

In the same way, the $addToSet operator adds a value to an array unless the value is already present, in which case $addToSet does nothing to that array. Like:

//document on mongodb, before the update
// { _id : "1", inviteGroup : [] }


//Invites from the request
// invites = [ { bidderId:"5e2350c7f88cfb331c4f67de", username:"artist1"} ];


//update method
Post.findByIdAndUpdate(
  { _id: req.params.id }, //req.params.id = "1"
  { $addToSet : { inviteGroup: { $each : invites } } },
  function(err, docs) {
    //...
  }
);

//document on mongodb, after the update
/*
{
  _id : "1",
  inviteGroup : [ { bidderId:"5e2350c7f88cfb331c4f67de", username:"artist1"} ]
}
*/

If you call the update method again with the same values:

Post.findByIdAndUpdate(
  { _id: req.params.id }, //req.params.id = "1"
  { $addToSet : { inviteGroup: { $each : invites } } },
  function(err, docs) { }
);

//the end document will be the same because the same value was already on the list:
/*
{
  _id : "1",
  inviteGroup : [ { bidderId:"5e2350c7f88cfb331c4f67de", username:"artist1"} ]
}
*/

Well, I hope that was what you looking for. =]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.