Обработка отношений «один ко многим» между двумя моделями в MongoDB - PullRequest
0 голосов
/ 26 ноября 2018

Я пытаюсь создать приложение электронной коммерции, используя MongoDB, Express и GraphQL (Apollo Client / Server) в бэкэнде, и у меня возникает проблема с тем, что пользователь добавляет что-то в свою корзину, которая хранится в БД.

На данный момент у меня есть три модели в моей БД: User, Item, CartItem.

Проблема, с которой я столкнулся, заключается в том, что у меня есть модель пользователя, которая имеет *Поле 1008 *, представляющее собой массив CartItem.

У меня есть модель CartItem, которая имеет item (отображает cartItem в корзине на исходную Item) и user ссылки.

После запуска мутации с внешнего интерфейса, у меня на сервере есть распознаватель addtoCart, который создает новый CartItem, если для этого user.id или item.id уже не существует CartItem, или просто обновляет количествоиз CartItem, если он существует.

addToCart: async (_, { id }, ctx) => {
  // 1. make sure they are signed in
  const { userId } = ctx.req;

  if (!userId) {
    throw new Error('You must be signed in!');
  }
  // 2. query the users current cart
  const existingCartItem = await CartItem.findOne({
    user: userId,
    item: id
  });

  // 3. check if that item is already in their cart and if it is increment by 1
  if (existingCartItem) {;
    return CartItem.findOneAndUpdate({
      _id: existingCartItem.id,
    }, {
      $set: {
        quantity: existingCartItem.quantity + 1
      }
    });
  }
  // 4. if its not, create a fresh CartItem for that user
  return CartItem({ user: userId, item: id }).save();
}

Это прекрасно работало для добавления нового CartItem и обновления количества, если оно уже существовало.Но поле cart для User не обновлялось с id для CartItem.Поэтому я добавил еще одну строку в свой преобразователь, чтобы обновить User и вставить cartItem.id в массив cart.

addToCart: async (_, { id }, ctx) => {
  // 1. make sure they are signed in
  const { userId } = ctx.req;

  if (!userId) {
    throw new Error('You must be signed in!');
  }
  // 2. query the users current cart
  const existingCartItem = await CartItem.findOne({
    user: userId,
    item: id
  });

  // 3. check if that item is already in their cart and if it is increment by 1
  if (existingCartItem) {
    return CartItem.findOneAndUpdate({
      _id: existingCartItem.id,
    }, {
      $set: {
        quantity: existingCartItem.quantity + 1
      }
    });
  }
  // 4. if its not, create a fresh CartItem for that user
  const cartItem = await CartItem({ user: userId, item: id }).save();

  //EXTRA: push cartItem id to User cart array
  await User.findOneAndUpdate({
    "_id": userId
  }, {
    $push: {
      cart: cartItem.id
    }
  });

  return cartItem
}

. Когда я делаю это, сервер начинает зависать, и любые вызовы API вызываютделает киоски и в основном ломает приложение без ошибок, которые я вижу.Если я удаляю код, который обновляет вызовы API User.cart, они снова работают, но возвращаются к User, который не обновляется.Я что-то упустил?

UserSchema выглядит так:

const mongoose = require('mongoose');
const { Schema } = mongoose;
mongoose.Promise = global.Promise;
const md5 = require('md5');
const validator = require('validator');
const mongodbErrorHandler = require('mongoose-mongodb-errors');
const passportLocalMongoose = require('passport-local-mongoose');

// document structure
const userSchema = new Schema({
  fullName: {
    type: String,
    required: 'Please supply a name',
    trim: true,
    lowercase: true
  },
  username: {
    type: String,
    required: 'Please supply a username',
    trim: true,
    lowercase: true
  },
  email: {
    type: String,
    unique: true,
    lowercase: true,
    trim: true,
    validate: [validator.isEmail, 'Invalid Email Address'],
    required: 'Please supply an email address'
  },
  password: {
    type: String,
    minlength: 6
  },
  resetToken: String,
  resetTokenExpiry: String,
  cart: [{
    type: mongoose.Schema.ObjectId,
    ref: 'CartItem'
  }],
  createdAt: {
    type: Date,
    default: Date.now
  },
  updatedAt: {
    type: Date,
    default: Date.now
  },
  permissions: [String],
});

// grab gravatar image based on email addresss
userSchema.virtual('gravatar').get(function() {
  const hash = md5(this.email);
  return `https://gravatar.com/avatar/${hash}?s=200`;
});

// grab first name and add as virtual field
userSchema.virtual('firstName').get(function() {
  return this.fullName.split(' ')[0];
});

// grab last name and add as virtual field
userSchema.virtual('lastName').get(function() {
  const names = this.fullName.split(' ');
  return names[names.length - 1];
});

// plugins
userSchema.plugin(passportLocalMongoose, { usernameField: 'email' });
userSchema.plugin(mongodbErrorHandler);

function autopopulate(next) {
  this.populate('cart');
  next();
}

userSchema.pre('find', autopopulate);
userSchema.pre('findOne', autopopulate);

// compile model and export
module.exports = mongoose.model('User', userSchema);

И моя схема CartItem выглядит так:

const mongoose = require('mongoose');
const { Schema } = mongoose;
mongoose.Promise = global.Promise;

// document structure
const cartItemSchema = new Schema({
  quantity: {
    type: Number,
    default: 1
  },
  item: {
    type: mongoose.Schema.ObjectId,
    ref: 'Item',
    require: 'You must supply a item'
  },
  user: {
    type: mongoose.Schema.ObjectId,
    ref: 'User',
    require: 'You must supply a user'
  },
  createdAt: {
    type: Date,
    default: Date.now
  },
  updatedAt: {
    type: Date,
    default: Date.now
  }
});

function autopopulate(next) {
  this.populate('item');
  this.populate('user');
  next();
}

cartItemSchema.pre('find', autopopulate);
cartItemSchema.pre('findOne', autopopulate);

// compile model and export
module.exports = mongoose.model('CartItem', cartItemSchema);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...