我正在尝试使用Node.js,Apollo Server v4,GraphQL,Mongoose技术创建类别树。
但是当我想获取创建的类别或子类别数据时,输出不是我想要的。类别既作为引用出现在子类别中,也作为普通类别出现。我还添加了具有此id 655 b105543598 f2 ef 0 ba 0 f69的类别数据,作为具有此id 655 b104 a43598 f2 ef 0 ba 0 f64值的类别的子类别数组中的第2个子类别。我不明白。但是虽然名字不出现空。
GraphQL查询请求;
query Query {
getCategories {
success
response_code
message
categories {
_id
name
attributes {
name
values {
value
}
}
products {
name
}
subCategories {
_id
name
attributes {
name
values {
value
}
}
products {
name
}
subCategories {
_id
name
attributes {
name
values {
value
}
}
products {
name
}
subCategories {
_id
name
attributes {
name
values {
value
}
}
products {
name
}
subCategories {
_id
name
attributes {
name
values {
value
}
}
products {
name
}
}
}
}
}
}
}
}
字符串
产出;
{
"data": {
"getCategories": {
"success": true,
"response_code": "categories-successfully-retrieved",
"message": "Categories Successfully Retrieved!",
"categories": [
{
"_id": "655b103b43598f2ef0ba0f5e",
"name": "K 2",
"attributes": {
"name": null,
"values": {
"value": null
}
},
"products": [],
"subCategories": []
},
{
"_id": "655b103e43598f2ef0ba0f61",
"name": "K 1",
"attributes": {
"name": null,
"values": {
"value": null
}
},
"products": [],
"subCategories": [
{
"_id": "655b104a43598f2ef0ba0f64",
"name": "AK 1",
"attributes": {
"name": null,
"values": {
"value": null
}
},
"products": [],
"subCategories": [
{
"_id": "655b105543598f2ef0ba0f69",
"name": null,
"attributes": null,
"products": null,
"subCategories": null
}
]
},
{
"_id": "655b106643598f2ef0ba0f6f",
"name": "AK 2",
"attributes": {
"name": null,
"values": {
"value": null
}
},
"products": [],
"subCategories": []
}
]
},
{
"_id": "655b104a43598f2ef0ba0f64",
"name": "AK 1",
"attributes": {
"name": null,
"values": {
"value": null
}
},
"products": [],
"subCategories": [
{
"_id": "655b105543598f2ef0ba0f69",
"name": "AAK 1",
"attributes": {
"name": null,
"values": {
"value": null
}
},
"products": [],
"subCategories": []
}
]
},
{
"_id": "655b105543598f2ef0ba0f69",
"name": "AAK 1",
"attributes": {
"name": null,
"values": {
"value": null
}
},
"products": [],
"subCategories": []
},
{
"_id": "655b106643598f2ef0ba0f6f",
"name": "AK 2",
"attributes": {
"name": null,
"values": {
"value": null
}
},
"products": [],
"subCategories": []
}
]
}
}
}
型
预期产出;
[
{
"name": "Category 1",
"attributes": {
"name": "Attribute Name",
"values": [{
"value": "Attribute Value",
"products": ["Product Ref", "Product Ref"]
}]
},
"products": ["Product Ref", "Product Ref"],
"subCategories": [
{
"name": "Sub Category 1",
"attributes": {
"name": "Attribute Name",
"values": [{
"value": "Attribute Value",
"products": ["Product Ref", "Product Ref"]
}]
},
"products": ["Product Ref", "Product Ref"],
"subCategories": [
{
"name": "Sub Category 2",
"attributes": {
"name": "Attribute Name",
"values": [{
"value": "Attribute Value",
"products": ["Product Ref", "Product Ref"]
}]
},
"products": ["Product Ref", "Product Ref"],
"subCategories": []
}
]
}
]
},
{
"name": "Category 2",
"attributes": {
"name": "Attribute Name",
"values": [{
"value": "Attribute Value",
"products": ["Product Ref", "Product Ref"]
}]
},
"products": ["Product Ref", "Product Ref"],
"subCategories": [
{
"name": "Sub Category 1",
"attributes": {
"name": "Attribute Name",
"values": [{
"value": "Attribute Value",
"products": ["Product Ref", "Product Ref"]
}]
},
"products": ["Product Ref", "Product Ref"],
"subCategories": [
{
"name": "Sub Category 2",
"attributes": {
"name": "Attribute Name",
"values": [{
"value": "Attribute Value",
"products": ["Product Ref", "Product Ref"]
}]
},
"products": ["Product Ref", "Product Ref"],
"subCategories": []
}
]
}
]
}
]
型
范畴 Mongoose 图式;
import mongoose from "mongoose";
const attributeSchema = new mongoose.Schema({
name: { type: String, required: true, trim: true, unique: true, default: "Default Name" },
values: [
{
value: { type: String, required: true, trim: true, unique: true },
products: [{ type: mongoose.Schema.Types.ObjectId, ref: "Product" }],
},
],
});
const categorySchema = new mongoose.Schema({
name: { type: String, required: true, trim: true },
subCategories: [{ type: mongoose.Schema.Types.ObjectId, ref: "Category" }],
attributes: [attributeSchema],
products: [{ type: mongoose.Schema.Types.ObjectId, ref: "Product" }],
});
export const Category = mongoose.model("Category", categorySchema);
型
类别GraphQL模式;
export const categorySchema = `#graphql
type Category {
_id: ID
name: String
subCategories: [Category]
attributes: Attributes
products: [Product]
}
input CategoryInput {
name: String!
isMainCategory: Boolean!
parentCategoryID: ID
}
type Attributes {
name: String
values: AttributesValue
}
type AttributesValue {
value: String
products: [Product]
}
input AttributesInput {
name: String!
categoryID: ID!
}
input AttributesValueInput {
value: String!
attributesID: ID!
}
type QueryCategoryResponse {
success: Boolean!
response_code: String!
message: String!
category: Category
categories: [Category]
}
type Query {
getCategories: QueryCategoryResponse
getCategoryByID(id: ID!): QueryCategoryResponse
getCategoriesByID(ids: [ID]!): QueryCategoryResponse
}
type Mutation {
createCategory(input: CategoryInput!): Response
}
`;
型
类别解析器;
import { Category } from "./model.js";
export const categoryResolver = {
Query: {
getCategories: async () => {
try {
const categories = await Category.find().populate("subCategories attributes products");
if (categories) {
return {
success: true,
response_code: "categories-successfully-retrieved",
message: "Categories Successfully Retrieved!",
categories: categories,
};
} else {
return { success: false, response_code: "categories-not-found", message: "Categories Not Found!" };
}
} catch (error) {
return { success: false, response_code: "server-error", message: "Server Error!" };
}
},
getCategoryByID: async (_, { id }) => {
try {
const category = await Category.findById({ _id: id }).populate("subCategories attributes products");
if (category) {
return {
success: true,
response_code: "category-successfully-retrieved",
message: "Category Successfully Retrieved!",
category: category,
};
} else {
return { success: false, response_code: "category-not-found", message: "Category Not Found!" };
}
} catch (error) {
return { success: false, response_code: "server-error", message: "Server Error!" };
}
},
getCategoriesByID: async (_, { ids }) => {
try {
const categories = await Category.find({ _id: { $in: ids } }).populate("subCategories attributes products");
if (categories.length !== 0) {
return {
success: true,
response_code: "categories-successfully-retrieved",
message: "Categories Successfully Retrieved!",
categories: categories,
};
} else {
return { success: false, response_code: "categories-not-found", message: "Categories Not Found!" };
}
} catch (error) {
return { success: false, response_code: "server-error", message: "Server Error!" };
}
},
},
Mutation: {
createCategory: async (_, { input }) => {
try {
if (input.isMainCategory) {
const category = await Category.findOne({ name: input.name }).collation({ locale: "en", strength: 2 });
if (category) {
return { success: false, response_code: "category-name-exist", message: "Category Name Exist!" };
} else {
const newCategory = new Category({
name: input.name,
});
await newCategory.save();
return {
success: true,
response_code: "category-created-successfully",
message: "Category Created Successfully!",
};
}
} else {
const category = await Category.findById(input.parentCategoryID).populate("subCategories");
if (!category) {
return { success: false, response_code: "sub-category-not-found", message: "Sub Category Not Found!" };
}
const categoryNames = category.subCategories.map((category) => category.name.toLowerCase());
if (categoryNames.includes(input.name.toLowerCase())) {
return { success: false, response_code: "category-name-exist", message: "Category Name Exists!" };
}
const newCategory = new Category({
name: input.name,
});
await newCategory.save();
category.subCategories.push(newCategory);
await category.save();
return {
success: true,
response_code: "sub-category-created-successfully",
message: "Sub Category Created Successfully!",
};
}
} catch (error) {
console.log(error);
return { success: false, response_code: "server-error", message: "Server Error!" };
}
},
},
};
型
我如何改进这段代码并解决我的getCategories输出问题?
显然,我也尝试过mongoose ref,我也尝试过根据categorySchema直接将数据发送到子类别中。我在第二个方法中提到的添加子类别的方法对我来说是一个头痛的问题。
1条答案
按热度按时间e5njpo681#
你的模型中似乎缺少了
parent
类别的概念。当定义一个层次模型时,通常包括对父类别的引用(类似于parentId
)。然后返回所有类别,首先搜索所有具有
null
parentId
的类别-这些是根节点。你还需要一个子类别的字段解析器来查找父类别是当前类别的类别。这允许你递归地遍历树。
GraphQL的一个限制是你必须明确你想在你的查询中带回多少层,你不能定义一个递归树,它会向下钻取到每一个可能的叶子。你上面的查询向下钻取5层。
首先,在GraphQL类型中,添加一个
parent
字段。字符串
在Mongoose模型中:
型
然后修改
getCategories
解析器以搜索parentId
为空的类别然后向
Category
类型添加一个字段解析器来解析基于parentId
的子类别,并添加一个字段解析器来解析父类别。现在,相对于您的
values
结构-您定义它的方式,它严格地位于Mongoose模型的内部;如果你想通过value
嵌套结果,那么你需要在Category
类型中添加一个value
字段,并定义一个包含value
和products
的Value
类型,即型
定义一个 plural
type
(例如:Attributes
)是不常见的。类型通常是单数的,因为如果你想要几个类型,你只需要把它们组成一个数组。你想在一个 field 名称中使用复数形式,而不是一个 type 名称。