Updating specific attribute for a specific user - mongodb

I am trying to update a specific attribute for a specific user in mongodb. I am having trouble understanding the nested-ness. Any help would be appreciated.
My specific problem is that I want to update a the activeID for a specific _cID that is specific to a User(a user can have many _cID's hence the array type in settings.
Here is the server call that I currently have
'updateActive' : function (p_id, c_id) {
Collections.Users.update({_id: Meteor.userId(), _cID: c_id},{$set: {'settings.$.activeID': p_id}});
}
and the schema
Schemas.CSettings = new SimpleSchema({
_id: {
type: String
},
_cID: {
type: String
},
activeID: {
type: String,
optional: true
}
});
Schemas.User = new SimpleSchema({
_id: {
type: String
},
createdAt: {
type: Date
},
profile: {
type: Schemas.UserProfile
},
settings: {
type: [Schemas.CSettings],
optional: true
}
});

Related

GraphQL Mutation Updating Users Followers with Mongoose/MongodDB - $set is empty error

I have this mutation set up:
followUser: {
type: UserType,
args: {
_id: { type: GraphQLString },
firebaseUid: { type: GraphQLString },
following: { type: new GraphQLList(GraphQLString)},
},
resolve(parentValue, { firebaseUid, _id, following}) {
const update = {
$set: { "following": [firebaseUid] },
$push: { "following": { firebaseUid } }
}
return UserSchema.findOneAndUpdate(
{ _id },
update,
{new: true, upsert: true}
)
}
},
I'm trying to add new followers into my graphql user's collection. My user model:
const UserSchema = new Schema(
{
firebaseUid: String,
following: [{ type: Schema.Types.ObjectId, ref: 'User' }],
followers: [{ type: Schema.Types.ObjectId, ref: 'User' }],
},
{ timestamps: true }
);
module.exports = mongoose.model("User", UserSchema);
So at first, the user doesn't have any followers, so it won't have that field yet. When user adds someone to their friends list, thats when the field will appear in mongodb. Right now I'm getting this error:
"message": "'$set' is empty. You must specify a field like so: {$set: {<field>: ...}}",
I'm not sure if I'm doing the $set correctly.
The UserType
const UserType = new GraphQLObjectType({
name: "User",
fields: () => ({
_id: { type: GraphQLString },
firebaseUid: { type: GraphQLString },
following: { type: new GraphQLList(GraphQLString) },
followers: { type: new GraphQLList(GraphQLString) },
...
})
});
edit:
current mongodb data collection:
_id: ObjectId("5e5c24111c9d4400006d0001")
name: "Mr. Smith"
username: "mrsmith"
after running the update
_id: ObjectId("5e5c24111c9d4400006d0001")
name: "Mr. Smith"
username: "mrsmith"
following: ["fdsaduybfeaf323dfa"] // <-- this gets added
Currently mongooses validator is rejecting the update. To fix this you need the following:
You only need to $push since it will automatically create an array if the property does not exist
You should remove the extra { } around the firebaseUid in the $push because otherwise the following array will contain objects with a firebaseUid property instead of directly containing the Uid (or would if the schema validator allowed it)
Mongo ObjectIds can only be converted from strings when they are 12-byte hexadecimal, and firebaseUid is not, so the schema should be typed to String instead of ObjectId as the validator will reject the field for update otherwise.

Pushing into array mongoose and mongo

I get the following error Cannot create field 'likes' in element whenever I am trying to push into my likeList array nested inside my comments.
When executing the following:
Feed.findOneAndUpdate(
{
owner: req.body.authorId,
"posts.comments.commentList._id": req.body.commentId
},
{
$push: {
"posts.$.comments.commentList.likes.likeList": {
user: req.user._id,
avatar: req.user.profile.profile_picture.url,
name: req.user.name
}
)
And my schema is as follows:
Feed Schema
owner: {
type: Schema.Types.ObjectId,
ref: "userType"
},
posts: [
{
author: {
userType: {
type: String,
enum: ["IndustryPartner", "User", "School"]
},
user: {
type: Schema.Types.ObjectId,
ref: "posts.author.userType", //<- This may cause an issue, if there are any issues with retrieving user fields, CHECK THIS
required: true
},
name: { type: String, required: true },
avatar: { type: String, required: true }
},
comments: {
totalComments: { type: Number, default: 0 },
commentList: [
{
likes: {
totalLikes: { type: Number, default: 0 },
likeList: [ <---//Trying to push here
{
user: { type: Schema.Types.ObjectId, ref: "User" },
avatar: { type: String },
name: { type: String },
date: {
type: Date,
default: Date.now
}
}
]
...
I am not sure if it's an issue with the query I am using in the first parameter to filter.
Update entire error message
It is odd because it appears that it is actually finding the correct commentList to go to, but is unable to access the likes field within the array itself. Am I wrong assuming that this should be able to step through it? posts.$.comments.commentList.likes.likeList
{ MongoError: Cannot create field 'likes' in element {commentList: [ { likes: { totalLikes: 0, likeList: [] },
_id: ObjectId('5cf6b3293b61fe06f48794e3'), user: ObjectId('5c9bf6eb1da18b038ca660b8'), avatar: "https://sli.blob.core.windows.net/stuli/
profile-picture-e1367a7a-41c2-4ab4-9cb5-621d2008260f.jpg", name: "Luke Skywalker", text: "Test comment from Luke", repliesToComment: [], date: new Date(1559671593009) } ]}
After further research, it appears the positional operator is no longer useful after stepping through 2 levels of arrays. So, the solution would be to use JS to change push the values into the array and then save them.

Mongoose Model containing arrays

First of all, I'm pretty new to MongoDB, Mongoose and Express. I'm trying to create a Mongoose model that has two arrays that I want to populate with multiple objects called itemSchema but I'm not sure how I'm supposed to update the array short of using findOneAndUpdate but since my array is initially empty there is no initial ID until a document is created. With the method that I have defined below - any already existing data in the food array is replaced by a new array. Below is my model -
const mongoose = require("mongoose");
const itemSchema = new mongoose.Schema({
id: String,
drinks: [
{
id: String,
name: {
type: String,
required: true
},
price: {
type: String,
required: true
},
description: {
type: String
},
date: {
type: Date,
default: Date.now
}
}
],
food: [
{
name: {
type: String,
required: true
},
price: {
type: String,
required: true
},
description: {
type: String
},
date: {
type: Date,
default: Date.now
}
}
]
});
module.exports = Item = mongoose.model("item", itemSchema);
I don't know if I'm defining the schema correctly. I know that it isn't very DRY ( since both arrays contain the same types ) but since I believe this is such a simple use case I don't want to define two separate schema for Drink and Food when I could just create one Schema.
router.post("/food", async (req, res) => {
try {
// Create an object from the request that includes the name, price and description
const newItem = {
name: req.body.name,
price: req.body.price,
description: req.body.description
};
// pass the object to the Items model
let item = new Items(newItem);
// add to the comments array
console.log("the new comment ", newItem);
item.food.unshift(newItem);
item.save();
// return the new item array to confirm adding the new item is working.
res.json(item);
} catch (error) {
// Display an error if there is one.
res.send(404).json(error);
}
});
The issue with the approach above comes from how I'm supposed to update the array. I defined the function below to update the food array for example but a new array gets created every single time. I believe that is has to do with not having Id param that I can use to provide the model with the findOneAndUpdate method. Any help would be greatly appreciated. Thank you in advance.
As per my opinion you can make your schema more simple as in your food and drinks array all the fields are same so you can simply take one more field as itemType and then you do not need to take two separate sub docs for food and drinks.
const mongoose = require("mongoose");
const itemSchema = new mongoose.Schema({
id: String,
itemType: { type: String }, // FOOD or DRINK
name: {
type: String,
required: true
},
price: {
type: String,
required: true
},
description: {
type: String
},
date: {
type: Date,
default: Date.now
}
});
If you wants to know more about updating in array with findOneAndUpdate() then i will explain two simple task to perform with this function.
CASE:1 If array of your sub doc is empty then you can push new document in your sub doc as below:
var updatedData = await Model.findOneAndUpdate(
{
_id: doc._id
},
{
$push: {
drinks: {
name: drink.name,
price: drink.price,
description: drink.description,
}
},
},{ new: true }
).lean().exec();
CASE:2 If you want to update existing sub doc by sub doc id then you can update as below:
var updatedData = await Model.findOneAndUpdate(
{
'drink._id': drinkId
},
{
$set: {
'drink.$.name': drink.name,
'drink.$.price': drink.price,
'drink.$.description': drink.description,
},
},{ new: true }
).lean().exec();

Mongo find users that are not blocked

I have a db in Mongo with users. I want to retrieve all user that are not in my blocked Array. tried to filter through the results by retrieving All documents but I wonder if that's the most efficient way. Is there a way in Mongo to find all users that are not part of an array?
Here is my User model:
var UserSchema = mongoose.Schema({
username: {
type: String,
index:true,
unique: true
},
password: {
type: String
},
email: {
type: String,
unique: true
},
name: {
type: String
},
latitude:{
type: String
},
longitude:{
type: String
},
blocked:{
type: Array
},
friends:{
type: Array
},
photo:{
type: String
},
identity:{
type: String
},
age:{
type: String
},
herefor:{
type: String
},
conns:{
type: Number
},
status:{
type: String
}
}, { collection: 'users' });
You are probably looking for something like the following, assuming your blocked users array contains usernames and your mongoose model is called UserModel:
var blockedUsernamesArray = [];
UserModel.find({ username: { $nin: blockedUsernamesArray } }, function(err, docs) {
// Handle result
})

Mongoose: How to query objects inside populate? [duplicate]

This question already has answers here:
Querying after populate in Mongoose
(6 answers)
Closed 6 years ago.
I have this route for searching partial user input for orderId.
ordersAdminRouter.route('/searchorder/:term')
.get(function(req, res){
term = req.params.term;
console.log(term);
Orders.find({orderId: new RegExp(term)})
.populate({ path: 'userPurchased products.product', select: '-username -password' })
.exec(function(err, orders){
if (err) throw err;
console.log(orders);
res.json(orders);
});
});
Here is my schema
var orderSchema = new Schema({
orderId: { type: String },
userPurchased: { type: Schema.Types.ObjectId, ref: 'users' },
products: [
{
product: { type: Schema.Types.ObjectId, ref: 'products' },
size: { type: String, required: true },
quantity: { type: Number, required: true },
subTotal: { type: Number, required: true }
}
],
totalQuantity: { type: Number },
totalPrice: { type: Number },
modeOfPayment: { type: String },
shippingAd: { type: String },
refNumber: { type: String },
isDone: { type: Boolean, default: false },
orderStatus: { type: String, default: 'Pending' },
dateOrdered: { type: Date, default: Date.now() },
fromNow: { type: String }
});
Now I need to search for the firstname and lastname inside userPurchased which I only get when I populate. How can search it?
I could not understand what kind of information you are saving in the 'userPurchased' field. I assume the users are in a different collection and you're only persisting the id of the user in the userPurchased. If you are just placing the id, you can search using the following query:
orderSchema.find({userPurchased : 'id'})
If you're putting an object with fields, there's no mystery either. Just use the . operator. For example:
orderSchema.find({userPurchased.firstName : 'name'})
Hope it helped you