MongoDB/Mongoose: Sorting within a populated field - node.js

I am pretty new to MongoDB and i am unable to find a solution to the following:
I am trying to sort personnel after their ranks.
CollectionPerson: _id, name, {rank_id}
CollectionRank: _id, RankName, level
What I am trying to accomplish ist to get a list in order of the rank level.
Any solution or direction pointing would be nice.
/edit:
MyModels:
const RankSchema = new Schema({
level: Number,
dgGrp: Number,
dgSold: String,
dgNATO: String,
hut: {
bezX: String,
bezM: String,
bezS: String,
img: String
},
lut: {
bezX: String,
bezM: String,
bezS: String,
img: String
},
mut: {
bezX: String,
bezM: String,
bezS: String,
img: String
}
});
const PersonalSchema = new Schema({
name: {
type: String,
required: true,
},
vname: String,
pNum: {
type: String,
default: '01010101',
},
pKenn: {
type: String,
default: '010101-A-01010',
},
dg: {
type: Schema.Types.ObjectId,
required: true,
ref: 'Rank'
},
uni: String,
sex: String,
konf: String,
adresse: {
str: String,
plz: Number,
ort: String,
land: String,
staat: String
}
});
My Query:
const personal = await Personal.find({}).populate({ path: 'dg', options: { sort: { level: 1 } } });

Population is done on client side by Mongoose after the query fetching the base documents has already executed. As such, sorting the base documents has already been done (if requested).
You can:
Construct an aggregation pipeline, $lookup and $sort yourself.
Let Mongoose populate your documents then reorder them as you wish in your application.

Related

Mongoose: Add validators on the fly on some parameters depending on queries

I am new to Mongoose and would like to know if it is possible to add validators on the fly on some parameters depending on queries. I have for example a schema like below:
var user = new Schema({
name: { type: String, required: true },
email: { type: String, required: true },
password: { type: String, required: true },
city: { type: String },
country: { type: String }
});
For a simple registration i force users giving the name, the email and the password. The Schema on top is OK. Now later I would like to force users giving the city and the country. Is it possible for example to update a user's document with the parameters city and country on required? I am avoiding to duplicate user schema like below:
var userUpdate = new Schema({
name: { type: String },
email: { type: String },
password: { type: String },
city: { type: String, required: true },
country: { type: String, required: true }
});
What you would need to do in this case is have one Schema and make your required a function which allows null and String:
var user = new Schema({
name: {
type: String,
required: true
},
email: {
type: String,
required: true
},
password: {
type: String,
required: true
},
city: {
type: String,
required: function() {
return typeof this.city === 'undefined' || (this.city != null && typeof this.city != 'string')
}
}
});
You can extract this and make it an outside function which then you can use for county etc.
What this does is it makes the field required but also you can set null to it. In this way you can have it null in the beginning and then set it later on.
Here is the doc on required.
As far as I know, no, it is not possible.
Mongoose schema are set on collection, not on document.
you could have 2 mongoose model pointing to the same collection with different Schema, but it would effectively require to have duplicated Schema.
personnally, in your situation, I would create a single home-made schema like data structure and a function who, when feeded with the data structure, create the two version of the Schema.
by example :
const schemaStruct = {
base : {
name: { type: String, required: true },
email: { type: String, required: true },
password: { type: String, required: true },
city: { type: String },
country: { type: String }
}
addRequired : ["city", "country"]
}
function SchemaCreator(schemaStruct) {
const user = new Schema(schemaStruct.base)
const schemaCopy = Object.assign({}, schemaStruct.base)
schemaStruct.addRequired.forEach(key => {
schemaCopy[key].required = true;
})
const updateUser = new Schema(schemaCopy);
return [user, updateUser];
}

Node.js Mongodb graphql

I have started a project that in using node.js and express and it's connected to a mongodb, this database has three collections (Participants, Houses, and activities), one participant can have one house and any activities! I have already done the query in graphql for each one, but I don't know how I can do the query and retrieve the relations between them. For example how I can know with participants are on a determined house...
Please go through the GraphQL documentation
GraphQL documentation out there tends to focus on queries, less on mutations, less on defining a schema, even less on setting up a server, and even less less on binding the server to an actual database.
type participant{
_id: String
title: String
participantId:String
........
house : house
}
type house{
_id: String
title: String
houseId:String
........
activities : [activity]
}
type activity{
_id: String
name: String
content: String
post: Post
}
This is sample model, you can design schema as per your requirement
Now you can try query like this
query {
participants{
_id
title
}
house {
_id
houseId
comments {
_id
postId
content
}
}
}
This is sample query format
My schema is:
type Participant {
_id: ID!,
CodP: String!,
User: String!,
Birth: Date,
Country: String,
Email: String,
ApplyDate: Date,
LUG: String,
Status: String,
Control: String,
CodH: House,
CodA: [Activitie],
createAt: Date,
updateAt: Date,
}
type Activitie {
_id: ID!,
CodA: String,
Day: String,
StartTime: Date,
EndTime: Date,
Where: String,
Name: String,
Description: String,
}
type House {
_id: ID!,
CodH: String,
Name: String,
Onwer: String,
Address: String,
Local: String,
Contact1: String,
Contact2: String,
Contact3: String,
Email: String,
URL: URL,
CoordDD: String,
CoordDMS: String,
URLGoogleMaps: URL,
IMG: String,
Group: String,
ImgGoogleMaps: String,
I1: String,
Info: String,
I2: String,
N1: String,
I3: String,
N2: String,
I4: String,
N3: String,
I5: String,
N4: String,
I6: String,
N5: String,
I7: String,
N6: String,
I8: String,
N7: String,
I9: String,
N8: String,
I10: String,
N9: String,
I11: String,
Final: String
}
type Query {
getParticipant(_id: ID): Participant
getParticipantAll: [Participant]
getActivitie(_id: ID): Activitie
getActivitieAll: [Activitie]
getHouse(_id: ID): House
getHouseAll: [House]
getHouseCod(CodH: String): [House]
}
But my problem in the Resolver, simples one i can do it, for example:
import House from '../../models/House';
export default {
getHouse: (_, { _id }) => House.findById(_id),
getHouseCod: (_, { CodH }) => House.find({CodH}),
// createdAt vai permitir ordenar pela data de criação //
getHouseAll: () => House.find({}).sort({ createdAt: -1 }),
};

mongoDB querying nested documents within a nested document

I'm having problems accessing user.info.name.familyName in a query. I'm newish to database design and queries and I don't know if its possible.
So here is the schema I have. Perhaps it might need to be redesigned for what I'm trying to do to work.
var UserSchema = mongoose.Schema({
username: {
type: String,
index: true,
required: true,
unique: true
},
password: {
type: String,
required: true
},
email: {
type: String,
required: true,
lowercase: true
},
emailVerified: {
type: Boolean,
default: false
},
info: {
name: {
givenName: String,
familyName: String,
},
address: {
street: String,
city: String,
state: String,
zipCode: String
},
primaryPhone: String,
cellPhone: String,
website: String,
licenseNumber: String,
title: String,
company: String
},
avatar: {
type: String,
default: '/images/avatar/default/contacts-128.png'
},
friends: [{ type: ObjectId, ref: User }],
friendRequests: [{ type: ObjectId, ref: User }]
});
I have a search function that currently searches by username or email and works fine, but I'd like it to also search by the users givenName or familyName. Here is the search function...
module.exports.search = function(searchValue, callback) {
var searchValue = new RegExp(`^${searchValue}`, 'i');
var query = {
$or: [
{username: searchValue},
{email: searchValue}
// {givenName condition here...}
]
}
User.find(query, callback).limit(10);
}
I tried this... and it didn't work
{info.name.givenName: searchValue}
I tried a few other nonsensical things but they also failed...
So to summarize my question, how would I either restructure the schema or query to be able to check the searchValue against user.info.name.givenName?
This way:
{'info.name.givenName': searchValue}
notice the quotes.
You were close :)

Swap an object in a Mongoose array with another object in the array of another document

Consider this schema:
let userSchema = new Schema({
email: { type: String, required: true },
password: { type: String, required: true },
books: [{
owner: String,
cover: String,
title: String,
link: String,
requestsReceived: { requestingUser: String, bookOffered: String },
requestsSent: { toUser: String, bookWanted: String },
beingRequested: { type: Boolean, default: false },
beingSent: { type: Boolean, default: false }
}],
ip: String
});
the books array contains objects which hold a variety of information. How can I take a certain book object from array of document 1 and swap it with array of document 2 preferably with the least amount of queries to the DB. (i.e. between two different user documents)
I know this is a bit difficult. Much appreciated.

mongoose sub populate not works

here is my schema :
var sourcesSchema = {
title: String,
name: String,
url: String,
description: String,
category: Array,
rating: Number,
source_pages: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'source_page',
}]
}
var sourcePageschema = {
uname: String,
source_name: String,
page_address: String,
driver_name: String,
product: {
type: mongoose.Schema.Types.ObjectId,
ref: 'products' //Edit: I'd put the schema. Silly me.
}
}
var productsSchema = {
title: String,
uname: String,
descriptin: String,
images: Array,
currency: String,
last_update_time: Number,
last_process_time: Number,
meta_data: {},
tags: Array,
min_price: Number,
max_price: Number,
prices: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'prices' //Edit: I'd put the schema. Silly me.
}]
}
this code works and populate the source_pages successfully :
_sources.find().populate('source_pages').exec(function (err,sources) {
res.json(200, sources);
});
but if I want to populate the product too :
_sources.find().populate('source_pages').populate('source_pages.product').exec(function (err,sources) {
res.json(200, sources);
})
this error :
TypeError: Cannot call method 'path' of undefined
at search (/home/sina/rhino2/node_modules/mongoose/lib/model.js:2088:28)
at search (/home/sina/rhino2/node_modules/mongoose/lib/model.js:2107:22)
at Function._getSchema (/home/sina/rhino2/node_modules/mongoose/lib/model.js:2114:5)
at populate (/home/sina/rhino2/node_modules/mongoose/lib/model.js:1719:22)
at Function.Model.populate (/home/sina/rhino2/node_modules/mongoose/lib/model.js:1702:5)
at cb (/home/sina/rhino2/node_modules/mongoose/lib/query.js:1690:11)
at /home/sina/rhino2/node_modules/mongoose/lib/utils.js:414:16
at /home/sina/rhino2/node_modules/mongoose/node_modules/mongodb/lib/mongodb/cursor.js:158:16
at commandHandler (/home/sina/rhino2/node_modules/mongoose/node_modules/mongodb/lib/mongodb/cursor.js:643:16)
at null. (/home/sina/rhino2/node_modules/mongoose/node_modules/mongodb/lib/mongodb/db.js:1641:20)
I was just hunting down the same problem, and I believe what you are looking for is this Mongoose: deep population (populate a populated field).
Basically, you are not able to do what you are trying to do, unless you do it in your callback function and then insert it in your return. I was trying to avoid that, but at the moment it seems like the only option. The other option, if you plan on doing a lot of this type of stuff, is to look into using a Relational DB.

Resources