How to get document with a specific collection of array - mongodb

I am trying to get a documents that has specific users in its users array
That is
Schema.books({
users:[ { type: mongoose.Schema.types.objectId, ref:'users' } ]
})
No am trying to get book documents with a specific number of users let's say two users.
I did try this
Let usersId = [ user1, user2 ]
Book.find().where(users).in(usersId)
But instead I get an array of all the user1 is a member of I am totally lost on what to do I really need your help

you need to use the $and operator. Without the $and operator you are querying for books that has userId1 or userId2
Book.find({
$and: [{ users: userId1 }, { users: userId2 }]
});
If your userId loop is large or not fixed you can do something like this:
Book.find({
$and: userIds.map(v => ({users:v}))
});

Related

How to build a MongoDB query that combines two field temporarily?

I have a schema which has one field named ownerId and a field which is an array named participantIds. In the frontend users can select participants. I'm using these ids to filter documents by querying the participantIds with the $all operator and the list of participantsIds from the frontend. This is perfect except that the participantsIds in the document don't include the ownerId. I thought about using aggregate to add a new field which consists of a list like this one: [participantIds, ownerId] and then querying against this new field with $all and after that delete the field again since it isn't need in the frontend.
How would such a query look like or is there any better way to achieve this behavior? I'm really lost right now since I'm trying to implement this with mongo_dart for the last 3 hours.
This is how the schema looks like:
{
_id: ObjectId(),
title: 'Title of the Event',
startDate: '2020-09-09T00:00:00.000',
endDate: '2020-09-09T00:00:00.000',
startHour: 1,
durationHours: 1,
ownerId: '5f57ff55202b0e00065fbd10',
participantsIds: ['5f57ff55202b0e00065fbd14', '5f57ff55202b0e00065fbd15', '5f57ff55202b0e00065fbd13'],
classesIds: [],
categoriesIds: [],
roomsIds: [],
creationTime: '2020-09-10T16:42:14.966',
description: 'Some Desc'
}
Tl;dr I want to query documents with the $all operator on the participantsIds field but the ownerId should be included in this query.
What I want is instead of querying against:
participantsIds: ['5f57ff55202b0e00065fbd14', '5f57ff55202b0e00065fbd15', '5f57ff55202b0e00065fbd13']
I want to query against:
participantsIds: ['5f57ff55202b0e00065fbd14', '5f57ff55202b0e00065fbd15', '5f57ff55202b0e00065fbd13', '5f57ff55202b0e00065fbd10']
Having fun here, by the way, it's better to use Joe answer if you are doing the query frequently, or even better a "All" field on insertion.
Additional Notes: Use projection at the start/end, to get what you need
https://mongoplayground.net/p/UP_-IUGenGp
db.collection.aggregate([
{
"$addFields": {
"all": {
$setUnion: [
"$participantsIds",
[
"$ownerId"
]
]
}
}
},
{
$match: {
all: {
$all: [
"5f57ff55202b0e00065fbd14",
"5f57ff55202b0e00065fbd15",
"5f57ff55202b0e00065fbd13",
"5f57ff55202b0e00065fbd10"
]
}
}
}
])
Didn't fully understand what you want to do but maybe this helps:
db.collection.find({
ownerId: "5f57ff55202b0e00065fbd10",
participantsIds: {
$all: ['5f57ff55202b0e00065fbd14',
'5f57ff55202b0e00065fbd15',
'5f57ff55202b0e00065fbd13']
})
You could use the pipeline form of update to either add the owner to the participant list or add a new consolidated field:
db.collection.update({},[{$set:{
allParticipantsIds: {$setUnion: [
"$participantsIds",
["$ownerId"]
]}
}}])

mongo: update subdocument's array

I have the following schema:
{
_id: objectID('593f8c591aa95154cfebe612'),
name: 'test'
businesses: [
{
_id: objectID('5967bd5f1aa9515fd9cdc87f'),
likes: [objectID('595796811aa9514c862033a1'), objectID('593f8c591ba95154cfebe790')]
}
{
_id: objectID('59579ff91aa9514f600cbba6'),
likes: [objectID('693f8c554aa95154cfebe146'), objectID('193f8c591ba95154cfeber790')]
}
]
}
I need to update "businesses.likes" where businesses._id equal to a center value and where businesses.likes contains certain objectID.
If the objectID exists in the array, I want to remove it.
This is what I have tried and didn't work correctly, because $in is searching in all the subdocuments, instead of the only subdocument where businesses._id = with my value:
db.col.update(
{ businesses._id: objectID('5967bd5f1aa9515fd9cdc87f'), 'businesses.likes': {$in: [objectID('193f8c591ba95154cfeber790')]}},
{$pull: {'businesses.$.likes': objectID('193f8c591ba95154cfeber790')}}
)
Any ideas how how I can write the query? Keep in mind that businesses.likes from different businesses can have the same objectID's.

Checking for similar records in mongodb across multiple fields.

In mongodb, I have a collection of people with the schema below. I need to write an aggregation to find possible duplicates in the database by checking:
If another person with same firstName, lastName & currentCompany exists.
Or, if another person with the same currentCompany & currentTitle exists.
Or, if another person has the same email (which is stored as an object in an array)
Or, if someone else has the same linkedIn/twitter url.
Is there a straightforward way of checking for duplicates based on the above cases w/ a mongodb aggregation? This question is close to what I'm looking for, but I need to check more than just one key/value.
{ _id: 'wHwNNKMSL9v3gKEuz',
firstName: 'John',
lastName: 'Doe',
currentCompany: 'John Co',
currentTitle: 'VP Sanitation',
emails:
[ { address: 'Anais.Grant#hotmail.com',
valid: true } ],
urls:
{ linkedIn: 'http://linkedin.com/johnDoe',
twitter: 'http://twitter.com/#john',
}
}
Thanks!
We can achieve it is using the following
$and, $or, $ne.
Note:- You need to feed one record as input for the conditions to match it with other records for eliminating the duplicates
I have given a sample query which will be filtering your collection for these two criterias, you can add the rest of your conditions to get the final result
If another person with same firstName, lastName & currentCompany exists.
Or, if someone else has the same linkedIn/twitter url.
db.yourcollection.find({
$and: [{
$or: [{
firstName: {
$ne: 'John'
}
}, {
lastName: {
$ne: 'Doe'
}
}, {
currentCompany: {
$ne: 'John Co'
}
}]
}, {
$or: [{
"urls.linkedIn": {
$ne: 'http://linkedin.com/Doe'
}
}]
}]
})

How to match criteria within object?

I'm having a Meteor chat application and try to delete all chats when a user removes the friendship. At the moment, I'm using this:
Friends.before.remove(function (userId, doc) {
// Delete Chats
Chats.find({users: {$elemMatch: {id: doc.user1, id: doc.user2}}}).forEach(function (docx) {
Chats.remove(docx._id);
})
});
Problem here: This code deletes ALL chats of a user, and not only the one where the match is correct. My chat document has a structure like this:
Chat
created_at: Date
users: [ {id: 'abc'}, {id: 'def'}]
last_message: Date
How can I remove all chats, that have both users in their arrays?
Use $all operator instead of $elemMatch.
$all
The $all operator selects the documents where the value of a field is an array that contains all the specified elements. To specify an $all expression, use the following prototype:
{ <field>: { $all: [ <value1> , <value2> ... ] } }
See MongoDB Docs.

Adding indexes in mogodb

I currently have a mongodb database which is pretty unstructured. I am attempting to extract all the followers of a given set of profiles on twitter. My database looks like this:
{'123':1
'123':2
'123':3
'567':8
'567':9
}
Where each key is a user and the value is a single follower. When I attempt to create an index on these keys, I simply run out of the available index as I have a lot of users (8 million). After googling, I find that the maximum number of indexes I can have is about 64. How do I create a proper indexing on this database? OR would you suggest a different way for me to store my data?
You should structure your data differently.
I would recommend you to have a collection of "user" documents, where every user has an array "followers". This array should be filled with unique identifiers of the users who follow (like name, _id or your own ID number).
{ name: "userA",
followers: [
"userB",
"userC"
]
},
{ name: "userB",
followers: [
"userD",
"userF"
]
},
You can then create an index on the followers field to quickly find all users who follow an other user. When you want to find all users who follow the users "userX", "userY" and "userZ", you would then do it with this query:
db.users.find({followers: { $all: ["userX", "userY", "userZ" ] } });
Edit:
To add a follower to a user, use the $push operator:
db.users.update({name:"userA"}, { $push: { followers: "userB" } } );
The $pull operator can be used to remove array enries:
db.users.update({name:"userA"}, { $pull: { followers: "userB" } } );