user6680
user6680

Reputation: 139

Adding array of objects to mongodb issue

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;
}

Upvotes: 0

Views: 176

Answers (3)

Eduardo Veras
Eduardo Veras

Reputation: 179

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. =]

Upvotes: 0

jhoanna
jhoanna

Reputation: 1857

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

Upvotes: 1

Arif Khan
Arif Khan

Reputation: 100

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);
            }
          }
        );

Upvotes: 0

Related Questions