Finding a match inside an object of an array field, using mongoose - node.js

I have this schema:
var eventSchema = new mongoose.Schema({
name: String,
tags: [{
tagId: mongoose.Schema.Types.ObjectId,
name: String,
description: String
}],
});
var Event = mongoose.model('Event', eventSchema);
And a array of tags ids, eg:
var arrayOfTagsIds = [23, 55, 71];
// in this example I'm not using real mongo id's, which are strings
How can I use mongoose's find to search Events that have any of these tags?
For example, this event should be in the results because it has tagId 23 and tagId 55:
{
_id: ...,
name: 'Football tournament',
tags: [{ tagId: 23, name: 'football', description: '' },
{ tagId: 55, name: 'tournament', description: '' }]
}
How must be the query inside find function?
I was thinking of using: tags.tagId: {$in: arrayOfTagsIds} but I don't think that is going to work (it doesn't sound okay to use tags.tagId, because tags is an array)
Event
.find({tags.tagId: {$in: arrayOfTagsIds}})
.exec(function (err, events) { ... }
Also, doing this kind of query is too slow?

Yes, you can use dot notation in keys for both embedded sub-documents and arrays. However, you do need to quote your key because it contains a dot:
Event
.find({'tags.tagId': {$in: arrayOfTagsIds}})
.exec(function (err, events) { ... }
To speed up this query you could create an index on 'tags.tagId'.

Related

$push into deeply nested array mongoose

my userSchema is as follows...
const userSchema = new mongoose.Schema({
firstName: { type: String },
lastName: { type: String },
movies: [
{
name: String,
duration: Number,
actors: [{ name: String, age: Number }]
}
],
});
In my NodeJS app with express I am trying to update my actors array to have another actor with value stroking from req.body.
I thought that I could do something like this...
await User.updateOne(
{
_id: req.user.id
movies._id: req.params.id
},
{
$push: { 'movies.actors': req.body }
}
)
I thought this would push an actor into the specified movie req.params.id but does nothing instead.
Try using positional operator $ in this way:
db.collection.update({
"_id": 1,
"movies._id": 1
},
{
"$push": {
"movies.$.actors": req.body
}
})
Note the only diference is the use of $. But with positional operator you are saying mongo where push the new data.
As docs says:
The positional $ operator identifies an element in an array to update without explicitly specifying the position of the element in the array.
So you can update the element movies.actors pushing new data without knowin the position of the element.
Example here
Try this:
await user.updateOne(
{$and:[{_id: req.user.id},{movie.name: 'I am Legend'}]},
{$set: { movies.actors:req.body}},
);

Mongoose: Find all rows without specyfic many data ( $ne )

I have a small problem in mongoose where I want to select all rows except the specified ids.
My code for example:
var ids = [{id: 123},{id: 222},{id:333}];
User.find({_id: {$ne: ids.id }},'firstName lastName _id avatar',function (err,users) {...});
Exact Problem:
I have a variable with many user ids, and I want to select only users without these ids.
We gonna use the $nin from mongodb, that exclude given array from the result.
We perform a map in order to have a plain array of id like [123, 222, 333]
const ids = [
{
id: 123,
}, {
id: 222,
}, {
id: 333,
}];
User.find(
// Query
{
_id: {
$nin: ids.map(x => x.id),
},
},
// Projection
'firstName lastName _id avatar',
// Callback
function (err,users) {...});

Efficiently querying indexed subarray using mongoose

I'm trying to store in MongoDB a collection of cards for each user. A collection is basically an array of owned cards with an associated quantity.
Collection {
user: ...,
cards: [ {cardId: 133, qty: 3}, {cardId: 22, qty: 1} ]
}
I'm building an API with node.js and mongoose where I receive a request in the form of [ {cardId: 133, qty: 2}, {cardId: 111, qty: 4} ].
Now I need to either create the card entry in the cards array if it doesn't exist or update the quantity if it is already there.
I need to do this efficiently as collections may contain thousands of cards so I came up with this Schema:
var OwnedCard = new Schema({
cardId: { type: String, index: true, required: true},
qty: { type: Number, required: true}
});
var Collection = new Schema({
userId: { type: String, index: true },
cards: [OwnedCard]
});
I'm not sure however how to take advantage of the index on cardId to quickly locate and update (or create if missing) cards in the subarray
Essentially, for each { cardId: ..., qty: xxx } in request => find/update, or create the right entry in the cards array.
So far I have (to locate the collection of the user):
Collection.findOne({userId: userId}, function (err, collection) {
var cards = collection.cards; // the cards
});
But I don't want to filter through them as a Javascript object since it doesn't take advantage of the index and might be slow, and instead look for a way to get mongo to retrieve the individual card entry quickly.
Any ideas on how to achieve this?

Get one element from an array of objects that's part of one document (mongoose)

I have a schema which contains Friends . Friends is an array where each element is an object that contains an id, gender, and emoji.
var userSchema = new Schema({
id: {
type: String,
unique: true,
required: true
},
gender: String,
Friends: [{
id: String
gender: String
emoji: String
}]
});
In the code below, I'm accessing one document which contains a Friends array and specifying that search with distinct such it only shows the document's array of Friends. I need to access only one element of that array that contains a specified id. Instead of filtering that array after the query like what's done in the code, is there a way to just get the element purely from the query? In other words, is there an extra functionality to distinct or some kind of mongoose operator that allows that?
User.findOne().distinct('Friends', { id: req.body.myId }).then(function(myDoc) {
var friendAtt = myDoc.filter(function(obj) {
return obj.id == req.body.id
})[0]
})
Thanks to bertrand I was able to find that the answer lies in 'Projection'. In mongodb it's '$', in mongoose its select. Here is how I made it work:
User.findOne({id: req.body.myId}).select({ Friends: {$elemMatch: {id: req.body.id}}}),
It only returns the element that matched the id specified in friends.
You don't really need distinct here, you can use find() on Friends.id and filter the first subdocument that match Friends.id with the positional parameter $ :
db.user.find(
{ 'id': 'id1', 'Friends.id': 'id2'},
{ 'Friends.$': 1 }
)
In mongoose :
User.find({ 'id': req.body.myId, 'Friends.id': req.body.id }, { 'Friends.$': 1 }).then(function(myDoc) {
console.log("_id :" + myDoc[0].Friends[0].id);
console.log("gender:" + myDoc[0].Friends[0].gender);
})

Don't know how to write complex Mongoose query

Here is the schema used to display current tournaments in one country:
var TournamentSchema = new mongoose.Schema({
name: String,
location: String,
googlelink: String,
description: String,
format: String,
date: Date
closedate:Date
type:String
});
The webpage also has filters like in ecommerce sites. If suppose I get one query from url like:
https://www.example.com/format=5v5%7v7&&location=hyd&&ahmedabad
I need to make query for tournaments which are 5v5 or 7v7 format and which are in Hyd and Ahmedabad.
I need to write generalised query as I don't know about number of places and format.
I don't know how to do this. Can someone help me out?
Here is an example of a query I wrote that uses mongoose $or.
Event.find( { $or: [{ joiners: req.user._id }, { creator: req.user._id}] } )
.populate('creator')
.exec(function(err, goevent){
if(err){
console.log(err)
} else {
res.json(goevent)
}
})
Basically in your query param {} you can pass in something like this:
{ $or: [ { query: one}, {query: two} ] }
Like so:
Model.find({ $or: [ { query: one}, {query: two} ] }, function(err, data){
//err & success handlers
}
Once you figure that out, you can use a bunch of other logical operators as well, like $and.
if the object you are querying is nested you just do 'some.property' (use string syntax when accessing objects with dot notation)

Resources