In MongoDb how to compare two arrays in find() method? - mongodb

I would like to compare two arrays in find() method. I did do that but it doesn seem to work :
var userOne = group.users[0];
var userTwo = group.users[1];
const selector = {
$and: [{
$or: [{
'users[0]': userOne
}, {
'users[0]': userTwo
}]
}, {
$or: [{
'users[1]': userOne
}, {
'users[1]': userTwo
}]
}, {
type: 0
}]
};
var exists = Groups.find(selector).fetch();
console.log(exists);
When userOne and userTwo exist, it doesnt return anything, but when one of them is undefined it returns all the collection.
Someone can help me please ?
Note:
Ths schema of the collection is :
GroupsSchema = new SimpleSchema({
name: {
type: String,
optional: true
},
description: {
type: String,
optional:true
},
type: {
type: Number
},
users: {
type: [String],
optional: true
} });

No need to use the $or operators here. You could try something like this (See this SO question for reference):
const selector = {
$and: [{
'users': userOne
},
{
'users': userTwo
},
{
type: 0
}]
};
Also, check the values in your database to make sure they are correct.

Related

MongoDB (mongoose): Cast to [string] failed for value

There's something wrong happens when I try to update a document in DB.
Here is Schema:
const prodSchema = new Schema({
name: {
type: String,
required: true,
unique: true
},
description: {
type: [String]
},
})
Then I get some product from elsewhere:
const some_product = axios.get(blah blah)
And update mu document.
Note that I set up a condition for a 'description': if it has a null value, it is updated - else it remains the same:
const newProduct = {
$set: {
name: some_product.name,
description: {
$cond: {
if: {
$eq: [null, '$description']
},
then: [some_product.description],
else: '$description'
}
}
}
}
Go update (I use mongoose):
Product.updateOne({name: some_product.name}, newProduct, {some params})
And I see this:
Cast to [string] failed for value
"[{"$cond":{"if":{"$eq":[null,"$description"]},"then":["Here is some
new description of the prosuct"],"else":"$description"}}]" at path
"description"
I think the point is that the type of description in the schema is array of strings, and 'description' field in the requested 'some_product' is just a string. May be this is the issue.
But how do I solve it?
Many thanks.
var description = []
description.push(some_product.description)
const newProduct = [{
$set: {
name: some_product.name,
description: {
$cond: {
if: {
$eq: [null, '$description']
},
then: description,
else: '$description'
}
}
}
}]
put update operation in [] use update pipeline
for example
model.update({},[{$set: ...}])

MongoDB - remove many from arrays of all existing elements

I have some simple user data. Here is example for one user:
const userSchema = new Schema({
userName: {
type: String,
},
projectsInput: [
{
type: Schema.Types.ObjectId,
ref: "Project",
},
],
projectsHold: [
{
type: Schema.Types.ObjectId,
ref: "Project",
},
],
});
I want by having ProjectId to be able to remove all records from all users that contains it.
if I get the first one
60f02d21159c4b4110f21a32
how I can perform updateMany function for my UserModel?
return UserModel.updateMany(
{
projectsInput: {
$elemMatch: args.projectId,
},
},
{
projectsInput: {
$slice: [projectsInput.$, 1],
},
}
);
})
Here is my code that is not working.
args.projectId = 60f02d21159c4b4110f21a32 (my id for the project I want to delete)
and UserModel is my mongodb Schema for user.
you can use $pull
{
$pull: {
projectsInputs: "123"
}
}

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.

MongoDB - Find and update an array object

I'm trying to update an object but I´m getting problems to update it. Please check the scheme:
const personSchema = new mongoose.Schema({
name: {
type: String,
required: true,
},
teachers: [
{
name: {
type: String,
},
information: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'info',
}],
},
],
I need to update an information inside this scheme Im trying to do (created is the object created):
const person = await ctx.models.person
.findOneAndUpdate({
teachers: {
$elemMatch: {
teachers: {
_id: input.processId,
},
},
},
},
{
$push: {
teachers: {
information: created,
},
},
}, {
new: true,
});
First of all, as recommended here by MongoDb official docs, you don't need $elemMatch:
If you specify only a single condition in the $elemMatch expression, you do not need to use $elemMatch.
Besides that, I recommend use the dot notation to search. Your code will be like that:
const person = await ctx.models.person
.findOneAndUpdate({
"teachers._id" : input.processId
},
{
$push: {
teachers: {
information: created,
},
},
}, {
new: true,
});

How to Check current user's vote before votes are grouped and sumed in same aggregate function

var PostSchema = new mongoose.Schema({
item: {
type: mongoose.Schema.ObjectId,
ref: 'item',
required: true
},
user: {
type: mongoose.Schema.ObjectId,
ref: 'User',
required: true
},
vote: {
type: Number,
default: 0
},
total: {
type: Number,
default: 0
},
awsPostKey: {type: String},
picture: {type: String, required: true}
});
var data = function(){
return Post
.find({})
.then(function(post){
return post;
})
};
var userId = //mongo objectId for current user
//postVote schema:
var PostVoteSchema = new mongoose.Schema({
post: {
type: mongoose.Schema.ObjectId,
ref: 'Post',
required: true
},
user: {
type: mongoose.Schema.ObjectId,
ref: 'User',
required: true
},
vote: {
type: Number,
default: 0
}
});
//pass data from Post query to PostVote sum function:
PostVoteSchema.statics.sum = function (data, userId) {
var postIds = data.map(function (a) {
return a._id;
});
return PostVote
.aggregate(
[
{ $match: { 'post': {$in: postIds}}},
{ $group: { _id:'$post' ,vote:{$sum:'$vote'}}}
])
.execAsync()
.then(function(votes){
return votes;
//desired output to client, _id is for specific post
{_id: 5802ea4bc00cb0beca1972cc, vote: 3, currentUserVote: -1}
});
};
I'm successfully able to get the total sum of all votes with the same postId.
Now, I"m wanting to see if the current user (userId) has placed a vote for the given post as well, then to return how they voted (+1 or -1) along with the sum of all votes for the specific post.
Is it possible to do this, or will I have to do this outside of my aggregate pipeline -- within a second query? It just seems potentially taxing to have to query the collection again.
Yes, that's possible. Within the $group pipeline, you can use the $cond operator as the logic for feeding the $sum accumulator operator. For example:
return PostVote.aggregate([
{ "$match": { "post": { "$in": postIds } } },
{
"$group": {
"_id": "$post",
"votes": { "$sum": "$vote" },
"userVotes": {
"$sum": {
"$cond": [
{ "$eq": ["$user", userId] },
"$vote",
0
]
}
}
}
}
]).execAsync().then(function(votes){
return votes;
});