unable to populate articles in mongoose [duplicate] - javascript

This question already has answers here:
How to convert string to objectId in LocalField for $lookup Mongodb [duplicate]
(1 answer)
Querying after populate in Mongoose
(6 answers)
Closed 4 years ago.
I have the category schema like this:
var category_article_Schema = new Schema({
"article_id": { type: String, required: false, unique: false },
"category": String,
"articles": [{ type: mongoose.Schema.Types.ObjectId, ref:'article'}],
});
var category_article_Schema = mongoose.model('category_article_Schema', category_article_Schema);
module.exports = category_article_Schema;
Article schema:
var articleSchema = new Schema({
"title": { type: String, required: true, unique: false },
"details": String,
"username": { type: String, required: true, unique: false },
"postImageUrl": String,
"url": String,
"categories": [String],
"created_at": { type: Date, default: Date.now }
});
var article = mongoose.model('article', articleSchema);
module.exports = article;
When I try to populate articles in the below function, I get only category id and name but no articles populated.
function getPostByCategory(req, res, next) {
category_article_model.find({category: req.params.name}) //sports
.populate('articles')
.exec()
.then(function(articlesByCategory) {
console.log(articlesByCategory);
})
.catch(function(err){
console.log('err ', err);
})
}
All the data I have in article collection is this:
`{
"_id": {
"$oid": "5b0008ce8787890004989df1"
},
"categories": [
"sports",
"health"
],
"title": "sample",
"details": "sample ",
"created_at": {
"$date": "2018-05-19T11:21:50.837Z"
},
"__v": 0
},
{
"_id": {
"$oid": "5b0087646dda9600049a9a27"
},
"categories": [
"sports"
],
"title": "sample3333",
"details": " sample3333",
"created_at": {
"$date": "2018-05-19T20:21:56.126Z"
},
"__v": 0
}`
And category_article_schema collection has:
{
"_id": {
"$oid": "5b0087646dda9600049a9a28"
},
"category": "sports",
"article_id": "5b0087646dda9600049a9a27",
"__v": 0
}
But the data returned is empty array of article:
[ { articles: [],
_id: 5b0008ce8787890004989df2,
category: 'sports',
article_id: '5b0008ce8787890004989df1',
__v: 0 } ]
I am not sure what could be the issue?

Related

Populate with condition return null in mongoose

I need to get all production results where machine name is 'CircuitPrinter'
ProductionResult schema:
import { Schema, model } from 'mongoose';
const schemaOptions = {
timestamps: { createdAt: 'created_at', updatedAt: false },
};
const productionResultSchema = new Schema({
machineId: { type: Schema.Types.ObjectId, ref: 'Machine' },
operatorId: { type: Schema.Types.ObjectId, ref: 'Operator' },
orderId: { type: Schema.Types.ObjectId, ref: 'Order' },
elementId: { type: Schema.Types.ObjectId, ref: 'Element' },
}, schemaOptions);
export default model('ProductionResult', productionResultSchema);
Machine Schema
import { Schema, model } from 'mongoose';
const schemaOptions = {
timestamps: { createdAt: 'created_at', updatedAt: 'updated_at' },
};
const machineSchema = new Schema({
name: { type: String },
status: { type: String },
date: { type: Date },
amount: { type: Number },
}, schemaOptions);
export default model('Machine', machineSchema);
Service function:
async getBar() {
return ProductionResult.find()
.populate({
path: 'machineId',
match: { name: 'CircuitPrinter' },
});
}
But in response I get machineId with null
Without match I get correct response with full machine data. What's wrong with my condition. Machine with CircuitPrinter name exist in database.
{
"_id": "608c532e4051960ef05176f4",
"machineId": null,
"elementId": "608c4e914051960ef05176cc",
"operatorId": "608c4e914051960ef05176d2",
"orderId": "608c4e914051960ef05176eb",
"created_at": "2021-04-30T18:57:50.771Z",
"__v": 0
}
Edited:
Sample data Machines document:
{
"_id": {
"$oid": "608c4e914051960ef05176ed"
},
"name": "CircuitPrinter",
"status": "Running",
"__v": 0,
"created_at": {
"$date": "2021-04-30T18:38:09.326Z"
},
"updated_at": {
"$date": "2021-04-30T18:38:09.326Z"
}
}
Sample data ProductionResult document:
{
"_id": {
"$oid": "608c532e4051960ef05176f4"
},
"machineId": {
"$oid": "608c4e914051960ef05176f0"
},
"elementId": {
"$oid": "608c4e914051960ef05176cc"
},
"operatorId": {
"$oid": "608c4e914051960ef05176d2"
},
"orderId": {
"$oid": "608c4e914051960ef05176eb"
},
"created_at": {
"$date": "2021-04-30T18:57:50.771Z"
},
"__v": 0
}

Sequelize: When querying data I want to accumulate a specific field in a nested array of objects on the top level of the returned instance

Sequelize 6.0:
I am using findOne on my User model and including Roles and Permissions (they're nested).
The resulting user instance looks (something) like this:
{
"id": "ID",
"username": "user1",
"email": "user#user.com",
"firstName": "User",
"lastName": "Last",
"role": "USER",
"spotifyId": "fakespotifyid10",
"createdAt": "2020-05-19T17:56:26.992Z",
"updatedAt": "2020-05-19T17:56:26.992Z",
"Role": {
"name": "USER",
"Permissions": [
{
"name": "createUser"
},
{
"name": "getUser"
},
{
"name": "updateUser"
}
]
}
}
While this is fine, it would be nice if I could accumulate all the permission names in a top level field named permissions. I believe there's a way to do this but I'm having trouble.
What I'd like the returned user instance to look like:
{
"id": "ID",
"username": "user1",
"email": "user#user.com",
"firstName": "User",
"lastName": "Last",
"role": "USER",
"spotifyId": "fakespotifyid10",
"createdAt": "2020-05-19T17:56:26.992Z",
"updatedAt": "2020-05-19T17:56:26.992Z",
"permissions": ['getUser', 'updateUser', 'createUser']
}
Here is the query for reference:
const findUserByEmailWithPermissions = email =>
User.findOne({
where: {
email,
},
include: [
{
model: Role,
attributes: ['name'],
include: [
{
model: Permission,
attributes: ['name'],
through: {
attributes: [],
},
},
],
},
],
})
Edit:
Here are the relevant associations:
User.belongsTo(Role, { foreignKey: { name: 'role', allowNull: false } })
Role.belongsToMany(Permission, {
through: RolePermission,
foreignKey: { name: 'roleName', allowNull: false },
})

Aggregate data from nested array

I need help with the aggregate framework.
I have a model (currencies field can contain more than one object):
const schema = new mongoose.Schema({
country: { type: String },
code: { type: String },
region: [{
name: { type: String },
path: { type: Array },
city: [{
name: { type: String },
path: { type: Array },
latitude: { type: String },
longitude: { type: String },
}],
}],
currencies: [{
code: { type: String },
name: { type: String },
symbol: { type: String },
}],
})
And I need to receive all currencies without duplicates.
Received data can view like this:
[
{ code: 'string', name: 'sting', symbol: 'string' },
{ code: 'string', name: 'sting', symbol: 'string' },
...
]
// or like this:
[
currencies: [
{ code: 'string', name: 'sting', symbol: 'string' },
{ code: 'string', name: 'sting', symbol: 'string' },
...
]
]
I try to create a query
Geo.aggregate([
{
$group: {
_id: null,
currencies: { $addToSet: '$currencies' },
},
},
])
but receive this data with duplicates and it has many nested arrays:
[
{
"_id": null,
"currencies": [
[
{
"_id": "5cd9486248989616a411fac5",
"code": "JPY",
"name": "Japanese yen",
"symbol": "¥"
}
],
[
{
"_id": "5cd9491a48989616a411fb47",
"code": "TRY",
"name": "Turkish lira",
"symbol": null
}
],
I try this query:
Geo.aggregate([
{
$addFields: {
code: '$currencies.code',
name: '$currencies.name',
symbol: '$currencies.symbol',
},
},
])
But I receive error "TypeError: item is not iterable".
I need little help )
Db data views like this:
{
"_id": {
"$oid": "5c3334a8871695568817eadf"
},
"country": "Singapore",
"code": "sg",
"region": [
{
"path": [
"Singapore"
],
"_id": {
"$oid": "5c3366c63d92ac6e531e05c0"
},
"city": [],
"name": "Central Singapore Community Development Council"
},
....
],
"__v": 0,
"currencies": [
{
"_id": {
"$oid": "5cd948ec48989616a411fb28"
},
"code": "BND",
"name": "Brunei dollar",
"symbol": "$"
},
{
"_id": {
"$oid": "5cd948ec48989616a411fb27"
},
"code": "SGD",
"name": "Singapore dollar",
"symbol": "$"
}
]
}
In aggregate pipeline first you need to unwind the currencies array and then group them by condition to get desired result.
Geo.aggregate([
{
$unwind: '$currencies'
},
{
$group: {
_id: null,
currencies: { $addToSet: '$currencies' },
},
},
])
For more information you can look into documentation here
db.temp.aggregate([
{$project : {currencies : 1}},
{$unwind: "$currencies"},
{
$addFields: {
currencyHash: {
$concat : ['$currencies.code', "--", "$currencies.name", "--", "$currencies.symbol"]
}
}
},
{
$group: {
_id: "$currencyHash",
currency : {
$first : "$currencies"
}
}
},
{
$project: {
code : "$currency.code",
name : "$currency.name",
symbol : "$currency.symbol"
}
},
{
$project: {
_id : 0,
currency : 0
}
}
]).pretty()

Creating a new table in mongoose based on object IDs

Hello the title of this question is very poorly worded however i will better explain the issue.
I have a document called 'buildings', and I also have two documents called 'rooms' and 'logins'. In both rooms and logins, they have an embedded document of building as follows:
Room Schema:
const roomSchema = new mongoose.Schema({
name: {
type: String,
required: true,
minlength: 1,
maxlength: 255
},
building: {
type: new mongoose.Schema({
name: {
type: String,
required: true,
minlength: 1,
maxlength: 255
}
}),
required: true
}
});
Logins Schema:
const loginSchema = new mongoose.Schema({
user: {
type: new mongoose.Schema({
email: {
type: String,
required: true
},
isVisitor: {
type: Boolean,
required: true
}
})
},
dateIn: {
type: Date,
required: true,
default: Date.now()
},
dateOut: {
type: Date
},
building: {
type: new mongoose.Schema({
name: {
type: String,
required: true
}
})
}
});
And the building schema is as follows:
const Building = mongoose.model(
"Building",
new mongoose.Schema({
name: {
type: String,
required: true,
minlength: 1,
maxlength: 255
},
address: {
type: String,
required: true,
minlength: 1,
maxlength: 255
},
postcode: {
type: String,
required: true,
minlength: 6,
maxlength: 8
},
organisation: {
type: new mongoose.Schema({
name: {
type: String,
required: true
}
})
}
})
);
Here is some examples of documents from each schema:
Building:
{
"_id": "5c79a31ed2016312ecd27c46",
"name": "TusPark",
"site": {
"_id": "5c79a243d2016312ecd27c45",
"name": "TusPark Newcastle"
},
"__v": 0
},
Rooms:
{
"_id": "5c7fa01abdd6233d6fdbc917",
"name": "E101",
"building": {
"_id": "5c79a31ed2016312ecd27c46",
"name": "TusPark"
},
"__v": 0
},
Logins:
{
"dateIn": "2019-03-21T13:13:23.069Z",
"_id": "5c938e151bd7a02d479893bd",
"user": {
"_id": "5c925378e88bb72764283108",
"email": "jack1#gmail.com",
"isVisitor": true
},
"building": {
"_id": "5c79a31ed2016312ecd27c46",
"name": "TusPark"
},
"__v": 0
}
I am trying to send a document to the client which contains the building details, with the rooms and logins embedded as attributes for the relevant building. The code I currently have written for this is below:
router.get("/all", async (req, res) => {
const buildings = await Building.find();
const rooms = await Room.find({
building_id: buildings._id
});
const logins = await Login.find({
building_id: buildings._id
});
const building_rooms = await Building.aggregate([
{
$lookup: {
from: "rooms",
localField: "building_id",
foreignField: "building_id",
as: "building_rooms"
}
},
{
$lookup: {
from: "logins",
localField: "building_id",
foreignField: "building_id",
as: "building_logins"
}
}
]);
res.send(building_rooms);
});
Note I have purposely not included $unwind
The current output for this request is:
[
{
"_id": "5c79a31ed2016312ecd27c46",
"name": "Park",
"site": {
"_id": "5c79a243d2016312ecd27c45",
"name": "Park Newcastle"
},
"__v": 0,
"building_rooms": [
{
"_id": "5c7fa01abdd6233d6fdbc917",
"name": "E101",
"building": {
"_id": "5c79a31ed2016312ecd27c46",
"name": "Park"
},
"__v": 0
},
{
"_id": "5c7fdbd12229db40589e41b5",
"name": "E202",
"building": {
"_id": "5c79a31ed2016312ecd27c46",
"name": "Park"
},
"__v": 0
}
],
"building_logins": [
{
"_id": "5c91483402d1a4145a2c4d9b",
"dateIn": "2019-03-19T19:51:06.458Z",
"user": {
"_id": "5c83b4b87321805bad025e65",
"email": "bob1999#gmail.com",
"isVisitor": true
},
"building": {
"_id": "5c79a31ed2016312ecd27c46",
"name": "Park"
},
"__v": 0,
"dateOut": "2019-03-20T11:55:19.205Z"
}
]
},
{
"_id": "5c925475e88bb72764283113",
"name": "Manchester",
"site": {
"_id": "5c921c94a922f6236cbe37d2",
"name": "Manchester"
},
"__v": 0,
"building_rooms": [
{
"_id": "5c7fa01abdd6233d6fdbc917",
"name": "E101",
"building": {
"_id": "5c79a31ed2016312ecd27c46",
"name": "Park"
},
"__v": 0
},
{
"_id": "5c7fdbd12229db40589e41b5",
"name": "E202",
"building": {
"_id": "5c79a31ed2016312ecd27c46",
"name": "Park"
},
"__v": 0
}
],
"building_logins": [
{
"_id": "5c91483402d1a4145a2c4d9b",
"dateIn": "2019-03-19T19:51:06.458Z",
"user": {
"_id": "5c83b4b87321805bad025e65",
"email": "bob1999#gmail.com",
"isVisitor": true
},
"building": {
"_id": "5c79a31ed2016312ecd27c46",
"name": "Park"
},
"__v": 0,
"dateOut": "2019-03-20T11:55:19.205Z"
}
]
}
]
However the issue is that the logins and rooms of 'Park' are being embedded in manchester building. which is not correct.
The correct output should be:
[
{
"_id": "5c79a31ed2016312ecd27c46",
"name": "Park",
"site": {
"_id": "5c79a243d2016312ecd27c45",
"name": "Park Newcastle"
},
"__v": 0,
"building_rooms": [
{
"_id": "5c7fa01abdd6233d6fdbc917",
"name": "E101",
"building": {
"_id": "5c79a31ed2016312ecd27c46",
"name": "Park"
},
"__v": 0
},
{
"_id": "5c7fdbd12229db40589e41b5",
"name": "E202",
"building": {
"_id": "5c79a31ed2016312ecd27c46",
"name": "Park"
},
"__v": 0
}
],
"building_logins": [
{
"_id": "5c91483402d1a4145a2c4d9b",
"dateIn": "2019-03-19T19:51:06.458Z",
"user": {
"_id": "5c83b4b87321805bad025e65",
"email": "bob1999#gmail.com",
"isVisitor": true
},
"building": {
"_id": "5c79a31ed2016312ecd27c46",
"name": "Park"
},
"__v": 0,
"dateOut": "2019-03-20T11:55:19.205Z"
}
]
},
{
"_id": "5c925475e88bb72764283113",
"name": "Manchester",
"site": {
"_id": "5c921c94a922f6236cbe37d2",
"name": "Manchester"
},
"__v": 0,
"building_rooms": [],
"building_logins": []
}
]
With there being no instances of building_rooms or building_logs as there are no logins or rooms with the object ID relating to manchester.
I really appreciate the time taken to read this and would be grateful for any help with solving tis problem.

How to show a nested object as a super object in MongoDB?

As it is stated here, I had to save reference objects inside of a nested key called 'item';
var userSchema = new Schema({
name: String,
connections: [{
kind: String,
item: { type: ObjectId, refPath: 'connections.kind' }
}]
});
var organizationSchema = new Schema({ name: String, kind: String });
var User = mongoose.model('User', userSchema);
var Organization = mongoose.model('Organization', organizationSchema);
In my DB, it is more like this:
var childSchema = new Schema({
kind: String,
item: {
type: Schema.Types.ObjectId,
refPath: 'children.kind'
}
},{ _id : false, strict:false });
var schema = new Schema({
name: String,
kind: String,
children: [childSchema]
},{
strict: false
});
Now, it is a tree based folder structure model, and it can have either a Folder or a Leaf as child object.
I needed a recursive populate, so I find an answer on SO, it became like this;
var autoPopulateChildren = function(next) {
this.populate({path:'children.item', select:'name id children'});
next();
};
schema.pre('findOne', autoPopulateChildren)
.pre('find', autoPopulateChildren)
Now, when I make a find query, I get this-like example;
{
"name": "Some Folder",
"children": [
{
"kind": "Leaf",
"item": {
"name": "First Level Leaf",
"id": "5b61c85f25375fddf6048d3c"
}
},
{
"kind": "Folder",
"item": {
"name": "First Level Folder",
"id": "5b61d844d77fb30b9537e5d1"
"children": [
{
"kind": "Leaf",
"item": {
"name": "Second Level Leaf",
"id": "5b61c85f25375fddf6048d3c"
}
}
]
}
}
],
"id": "5b61c85f25375fddf6048d3d"
}
But now, I need to get rid of 'kind' (don't show) and also I need to show 'item' object as a child (it should be name instead of item:{name:'a'}:
{
"name": "Some Folder",
"children": [
{
"name": "First Level Leaf",
"id": "5b61c85f25375fddf6048d3c"
},
{
"name": "First Level Folder",
"id": "5b61d844d77fb30b9537e5d1"
"children": [
{
"name": "Second Level Leaf",
"id": "5b61c85f25375fddf6048d3c"
}
]
}
],
"id": "5b61c85f25375fddf6048d3d"
}
How can I do this on autoPopulateChildren function?

Categories

Resources