Combining result of two different Queries from two different Model MongoDB - javascript

So first I have a query that finds books that has been borrowed by user, it will search using the Borrow model
const bookqueryinitial = await Borrow.find({borrower_Id : String(_id), borrowStatus: req.query.status}).sort({"borrowDate": -1 }).skip(skip).limit(pageSize);
it will return results like this
[
{
_id: new ObjectId("628ebcc10944a1223397b057"),
borrower_Id: '6278d1b6b4b7659470572e19',
borrowedbook_Id: '62710ac63ad1bfc6d1703162',
borrowStatus: 'pending',
borrowDate: 2022-05-25T23:33:21.849Z,
__v: 0
},
{
_id: new ObjectId("628d9c0b9a3dc72f4aa72f1a"),
borrower_Id: '6278d1b6b4b7659470572e19',
borrowedbook_Id: '62710ac63ad1bfc6d170314d',
borrowStatus: 'pending',
borrowDate: 2022-05-25T03:01:31.416Z,
__v: 0
}
]
next is I will map through the borrowedbook_Ids of the result and store them in an array
const booksinsidequery = bookqueryinitial.map(bookids=>{
return bookids.borrowedbook_Id
})
then I will search the ids that is stored in array and search for those ids in the Book model
const bookquery = await Book.find({ '_id': { $in: booksinsidequery } });
\\and the result is somethign like this
[
{
_id: new ObjectId("62710ac63ad1bfc6d170314d"),
title: "Girl who kicked the Hornet's Nest",
author: 'Larsson, Steig',
genre: [ 'fiction' ],
publisher: '',
dateOfPublication: 2017-10-25T00:00:00.000Z,
noOfCopies: 14,
type: 'Article',
form: 'Fiction',
isbn: '978-69793-4824559-56755-9',
dateAdded: 2003-04-23T00:00:00.000Z,
noOfBookmarks: [ [Object] ],
noOfLikes: [],
},
{
_id: new ObjectId("62710ac63ad1bfc6d1703162"),
title: 'We the Nation',
author: 'Palkhivala',
genre: [ 'philosophy' ],
publisher: '',
dateOfPublication: 2011-11-22T00:00:00.000Z,
noOfCopies: 94,
type: 'Book',
form: 'Non-fiction',
isbn: '978-65685-4156343-802140-8',
dateAdded: 2010-06-08T00:00:00.000Z,
noOfLikes: [],
noOfBookmarks: []
}
]
Now before sending the result of the query to the client side, I want to bind my initial queries from Borrow model to my Book model and the final result should be like this
[
{
_id: new ObjectId("62710ac63ad1bfc6d170314d"),
title: "Girl who kicked the Hornet's Nest",
author: 'Larsson, Steig',
genre: [ 'fiction' ],
publisher: '',
dateOfPublication: 2017-10-25T00:00:00.000Z,
noOfCopies: 14,
type: 'Article',
form: 'Fiction',
isbn: '978-69793-4824559-56755-9',
dateAdded: 2003-04-23T00:00:00.000Z,
noOfBookmarks: [ [Object] ],
noOfLikes: [],
//added properties based on matched condition (Borrow.borrowedbook_Id === Book._id)
borrowStatus: 'pending',
borrowDate: 2022-05-25T03:01:31.416Z,
},
{
_id: new ObjectId("62710ac63ad1bfc6d1703162"),
title: 'We the Nation',
author: 'Palkhivala',
genre: [ 'philosophy' ],
publisher: '',
dateOfPublication: 2011-11-22T00:00:00.000Z,
noOfCopies: 94,
type: 'Book',
form: 'Non-fiction',
isbn: '978-65685-4156343-802140-8',
dateAdded: 2010-06-08T00:00:00.000Z,
noOfLikes: [],
noOfBookmarks: [],
//added properties based on matched condition (Borrow.borrowedbook_Id === Book._id)
borrowStatus: 'pending',
borrowDate: 2022-05-25T23:33:21.849Z,
}
]
How can I attain these results?

You can achieve this with the aggregation framework that MongoDB provides.
Based on your data here is an example: https://mongoplayground.net/p/DQJIbcqBDKM
Lookup : the operator helps you to join data between different collections and the matched data will be in an array. In this case, called borrows
Unwind : will create a document per item on a specified array
Addfields : Allows you to create new attributes, in this case, the two that you wanted "borrowStatus" and "borrowDate"
Project : this operator allows you to hide or show data in the next stage. In this case, 0 means that we will hide a specific attribute

Related

Adding element inside nested array in mongoose

Server Started at Port 3000...
{
_id: new ObjectId("61c707e9f4ff040a47d27c3f"),
username: 'adityaaryam',
password: '1234',
nameOfUser: 'Aditya Aryam',
emailOfUser: 'adityaaryam#gmail.com',
userAllLists: [
{
name: 'Hello',
items: [],
_id: new ObjectId("61c70d915448262d1dca1a69")
},
{
name: 'Work',
items: [],
_id: new ObjectId("61c70d965448262d1dca1a70")
},
{
name: 'Home Work',
items: [],
_id: new ObjectId("61c70d9b5448262d1dca1a79")
},
{
name: 'Hello',
items: [],
_id: new ObjectId("61c70e7f5448262d1dca1a84")
},
{
name: 'Play',
items: [],
_id: new ObjectId("61c7126a5448262d1dca1a9b")
},
{
name: 'Eat',
items: [],
_id: new ObjectId("61c71325b0219e6ce4f57990")
},
{
name: 'Walla',
items: [],
_id: new ObjectId("61c7197de9564390d506cbe9")
}
],
__v: 7
}
This is how my database looks like. I want to push new elements to "items" array which is nested inside the "userAllLists" array using mongoose. How do I implement this?
I have been trying findOneAndUpdate using $push but I am not able to achieve my desriable results.
My Schemas are as follows:
const itemSchema = {
name: String
};
const customListSchema ={
name:String,
items:[itemSchema]
};
const userSchema={
username: String,
password: String,
nameOfUser: String,
emailOfUser: String,
userAllLists: [customListSchema],
};
Thanks in Advance!
I think $push is the right way to push new elements to nested arrays, you didn't show the code you tried to see if it works or not, at all here is an example based on your schema
User.update({_id: "61c707e9f4ff040a47d27c3f", }, {
'$push': {
"userAllLists.$[].items": {name: "test item name"}
}
});
Note: $[] expressions will push the specified object inside all items arrays that exist in userAllLists
To push the item for only specific userAllLists object you can use the following syntax
User.update({_id: "61c707e9f4ff040a47d27c3f", "usersAllLists._id": "61c70d915448262d1dca1a69"}, {
'$push': {
"userAllLists.$.items": {name: "test item name"}
}
});
this will ensure to push the item object to the specified usersAllLists object which has this id 61c70d915448262d1dca1a69

What does this 'child' in my javascript array mean?

I keep getting these 'child' things in my Javascript collection after certain operations. The 'child' keyword is showing up in my terminal after logging the Javascript collection.
Whats strange is that I can't actually find good documentation anywhere online on what this means. Seems like it should be a basic concept.
When I do google it I just get a ton of results for 'child' in context of HTML and the DOM.
What does it mean in javascript? And how could I fix this collection to have these nested collections without the 'child' thing.
Gosh I wish I could speak about it with more sophistication :p
More Context on How This 'Bad' Collection is Generated
So I'm trying to populate JSON data from my Mongodb database and return it to the frontend. Essentially I have nested collections like so:
Institution
|
------------> memberOrganizations
|
---------------------> associatedVIPs
Where I'm originally grabbing Institutions I can populate collections one level down using built in populate functionality.
Doing like so:
Institution.find()
.populate('memberOrganizations')
.then(function (institutions) {
console.log("All institutions, memberOrganizations populated no problem.");
return res.json(institutions);
});
The problem is coming in when I try to go populate collections inside those member organizations, and replace existing memberOrganizations data with that.
Institution.find()
.populate('memberOrganizations')
.then(function (institutions) {
var populateOrganizationOrderManagers = _.map(institutions, function (institution) {
var masterInstitution = _.cloneDeep(institution);
return new Promise(function (resolve, reject) {
var ids = _.map(institution.memberOrganizations, 'id');
Organization.find(ids).populate('associatedVIPs').then(function (orgs) {
masterInstitution.memberOrganizations = orgs;
resolve(masterInstitution);
});
});
});
return Promise.all(populateOrganizationOrderManagers)
.then(function (institutionsWithOrderManagers) {
return res.json(institutionsWithOrderManagers);
});
})
Printouts of the JSON data using console.log to print to my terminal
(Simplified all data by a bit to make it easier to make a point)
What it looks like:
[ child {
memberOrganizations:
[ { associatedVIPs:
[ { firstName: 'Gregory',
lastName: 'Parker',
email: 'info#parker2018.com',
id: '5ab94183164475010026184b' } ],
institution: '5ab940b71644750100261845',
name: 'Greg Parker',
type: 'Student',
id: '5ab941401644750100261847' },
{ associatedVIPs:
[ { firstName: 'Irma',
lastName: 'Francisco',
email: 'irmaf#houstontransporter.com',
id: '5ae348da1ef63b245a74fe2d' } ],
institution: '5ab940b71644750100261845',
name: 'Transporter Inc',
type: 'Other',
id: '5ae3488d1ef63b2c8f74fe29' } ],
name: 'Corporate',
createdAt: 2018-03-26T18:49:27.955Z,
updatedAt: 2018-07-05T15:00:02.562Z,
id: '5ab940b71644750100261845' }
What I'd like it to look like:
{ memberOrganizations:
[ {
name: 'Tau Kappa Epsilon',
type: 'Greek - Fraternity',
institution: '5a3996d47bab3401001cc1bc',
id: '5a3ae7ebdfd69201001aa54d'
associatedVIPs:
[ { firstName: 'Irma',
lastName: 'Francisco',
email: 'irmaf#houstontransporter.com',
id: '5ae348da1ef63b245a74fe2d' },
{ firstName: 'Zach',
lastName: 'Cook',
email: 'zach#google.com',
id: '5ae348da1ef63b245a74f' } ]
},
{ name: 'Farmhouse',
type: 'Greek - Fraternity',
institution: '5a3996d47bab3401001cc1bc',
id: '5a4e71e806b97a01003bd313' } ],
name: 'Troy University',
createdAt: '2017-12-19T22:46:44.229Z',
updatedAt: '2018-07-05T15:18:03.182Z',
id: '5a3996d47bab3401001cc1bc' },
{ memberOrganizations:
[ { name: 'Alpha Epsilon Pi',
type: 'Greek - Fraternity',
institution: '5a4d534606b97a01003bd2f1',
id: '5a4f95c44ec7b6010025d2fb' },
{ name: 'Alpha Delta Chi',
type: 'Greek - Sorority',
institution: '5a4d534606b97a01003bd2f1',
id: '5a74a35e1981ef01001d0633' },
{ name: 'Phi Sigma Kappa',
type: 'Greek - Fraternity',
institution: '5a4d534606b97a01003bd2f1',
id: '5a7ba61821024e0100be67b7' } ],
name: 'University of Alabama',
createdAt: '2018-01-03T22:03:50.929Z',
updatedAt: '2018-07-05T15:18:03.182Z',
id: '5a4d534606b97a01003bd2f1' }

Mongoose find and findOne return entire collection

I have the code below in javascript and the database is already populated. Now when I use either find() or findOne(), Mongoose returns the entire collection of over 6000 entries. Why is the filter not happening?
var tickerIDSchema = new mongoose.Schema({
ticker: String,
name: String,
exchange: String,
"_id": false
});
var tickerListSchema = new mongoose.Schema({
complete: [tickerIDSchema]
});
tickerListSchema.index(
{ "complete.ticker": 1, "complete.exhcange": 1 },
{ unique: true }
);
var tickerList = mongoose.model("tickerList", tickerListSchema);
tickerList.findOne({"complete.ticker": "BMO"}, function(err, data){
console.log(data)
})
Result:
{ _id: 5a44452bb1dac235f039c66c,
__v: 0,
complete:
[ { ticker: 'AAPL', name: 'Apple Inc.', exchange: 'Nasdaq' },
{ exchange: 'Amex',
name: 'Altisource Asset Management Corp',
ticker: 'AAMC' },
{ exchange: 'Amex',
name: 'Almaden Minerals, Ltd.',
ticker: 'AAU' },
{ exchange: 'Amex',
name: 'Aberdeen Emerging Markets Smaller Company Opportunities Fund I',
ticker: 'ABE' },
{ exchange: 'Amex',
name: 'Acme United Corporation.',
ticker: 'ACU' },
{ exchange: 'Amex', name: 'AeroCentury Corp.', ticker: 'ACY' },
{ exchange: 'Amex',
name: 'Adams Resources & Energy, Inc.',
ticker: 'AE' },
{ exchange: 'Amex', name: 'Ashford Inc.', ticker: 'AINC' },
{ exchange: 'Amex',
name: 'Air Industries Group',
ticker: 'AIRI' },
... 6675 more items ] }
You appear to have an extra layer of abstraction that is unnecessary.
This code effectively creates a document with a single attribute.
var tickerListSchema = new mongoose.Schema({
complete: [tickerIDSchema]
});
The result is that you have a single document in your mongodb collection tickerList that contains all of your data within that single attribute, complete. Per the mongodb documentation (https://docs.mongodb.com/manual/reference/method/db.collection.findOne/), findOne should return the matching document. Because you are querying for a subdocument, the returned result is the parent document, which contains all of the data you have in your tickerIDSchema
To achieve your desired results, your mongoose code should probably look something like this.
var tickerIDSchema = new mongoose.Schema({
ticker: String,
name: String,
exchange: String,
"_id": false
});
tickerIDSchema.index(
{ "ticker": 1, "exchange": 1 },
{ unique: true }
);
var tickerList = mongoose.model("tickerList", tickerIDSchema);
tickerList.findOne({"ticker": "BMO"}, function(err, data){
console.log(data)
})
Removing the tickerListSchema will allow you to query the tickerIDSchema directly. The findOne() query would appear as shown, and find() should operate as follows:
tickerList.find({}, function(err, data){
console.log(data)
})

Nested object text search in mongoDB

I am not sure how I am going to solve this problem:
I want to search in a mongoDB collection and return only the nested objects that fits the search query (using text search on all of the fields).
All documents in the collection have this format:
{
arr: [
{
_id: 1,
name: 'Random',
description: 'Hello world'
},
{
_id: 2,
name: 'World',
description: 'This is a random description'
},
{
_id: 3,
name: 'Random',
description: 'Hi'
}
]
}
In this case, if my search query is 'world', then this should be the result:
[
{
_id: 1,
name: 'Random',
description: 'Hello world'
},
{
_id: 2,
name: 'World',
description: 'This is a random description'
},
//... objects from other documents in the collection that fits the query
]
If this is not possible in mongoDB, are there any JavaScript libraries that can achieve this? Would greatly appreciate the help!
With the aggregation framework it could look like so
db.getCollection('yourCollection').aggregate([
{
$unwind: '$arr'
},
{
$match: {
$or: [
{ 'arr.name': /world/i },
{ 'arr.description': /world/i }
]
}
},
{
$project: {
_id: '$arr._id',
name: '$arr.name',
description: '$arr.description'
}
}
])
which will result in the following output for your example data:
{
"_id" : 1,
"name" : "Random",
"description" : "Hello world"
}
{
"_id" : 2,
"name" : "World",
"description" : "This is a random description"
}
If you have the need for a single array with the resulting documents as shown in your question, you can simply chain a toArray() call at the end of the pipeline - keep in mind though that this may cause increased memory consumption in case of large result sets as pointed out by SSDMS in the comments.

Saving Mongoose documents with empty sub-documents collections results in duplicate key error

I have two mongoose schemas:
var productSchema = new Schema({
name: { type: String, required: true, unique: true },
...
});
...
var categorySchema = new Schema({
...
products: [ProductSchema]
});
When I try to save categories
var categories = [
{..., products: []},
{..., products: []}
];
or even without products
var categories = [
{...},
{...}
];
I'm getting error
{ [MongoError: E11000 duplicate key error index: test.categories.$products.name_1 dup key: { : undefined }]
name: 'MongoError',
err: 'E11000 duplicate key error index: test.categories.$products.name_1 dup key: { : undefined }',
code: 11000,
n: 0,
lastOp: { _bsontype: 'Timestamp', low_: 6, high_: 1404282198 },
ok: 1 }
It seems like mongoose is trying to save products with undefind names.
Mongoose log before getting error:
Mongoose: categories.insert({ __v: 0, products: [], _id: ObjectId("53b3c167d28a86102dec420a"), order: 1, description: 'Category 1', name: 'Cat 1' }) {}
Mongoose: categories.insert({ __v: 0, products: [], _id: ObjectId("53b3c167d28a86102dec420b"), order: 2, description: 'Category 2', name: 'Cat 2' }) {}
If I remove unique: true from the name property of productSchema two categories are added with empty products [] collections.
What am I doing wrong?
Thank you!
This is pretty normal really. The empty array is essentially considered to be a "null" value for the "products.name" field, that of course violates the unique constraint on the index.
You could essentially "skip" any values of "name" that are in fact undefined, and you do this by adding the "sparse" property to the index. In the present schema path form:
var productSchema = new Schema({
name: { type: String, required: true, unique: true, sparse: true }
});
var categorySchema = new Schema({
products: [productSchema]
});
Now as long as there is no value in "name" there will be no problem unless of course it actually exists somewhere. Make sure to drop the index already created first though.
Just a note, be aware that what this is doing is making sure that the "products.name" values are unique for the "whole" collection. If you are just trying to make sure they are unique for a given category, then indexing is not your solution and you need to ensure that by other means.

Categories

Resources