英文:
Is it possible to use a variable object inside collection.find() in mongoose?
问题
我试图编写“高级搜索”选项的后端代码,这是一个我用来练习JS,MongoDB(Mongoose),Next,Node等编码的项目。
我正在使用的模式如下:
House Schema:{
name:String,
address:{
street:String
city:String,
state:String
},
operations:{
rent:Boolean,
shortRent:Boolean,
purchase:Boolean,
agentRentPrice:Number,
agentShortRentPrice:Number,
agentSellingPrice:Number},
features:{
bathrooms:Number,
bedrooms:Number,
beds:Number,
amenities:[String],
},
}
现在,前端发送以下信息(在req.body中):
query = {
name: null,
address: { city: null, state: null },
operations: {
rentAvailable: false,
purchaseAvailable: false,
shortRentAvailable: false,
agentRentPriceMin: null,
agentSellingPriceMin: null,
agentShortRentPriceMin: null,
agentRentPriceMax: null,
agentSellingPriceMax: null,
agentShortRentPriceMax: null,
},
features: {
bathroomsMin: null,
dormsMin: null,
bedsMin: null,
amenities: null,
},
}
当然,这些“null”值将被用户输入的数字或字符串替换。
然后,我声明另一个对象:
let queryObj = {
name: query.name,
address: { city: query.address.city, state: query.address.state },
operations: {
rentAvailable: query.operations.rentAvailable,
purchaseAvailable: query.operations.purchaseAvailable,
shortRentAvailable: query.operations.shortRentAvailable,
agentRentPrice: {
$gte: query.operations.agentRentPriceMin,
$lte: query.operations.agentRentPriceMax,
},
agentSellingPrice: {
$gte: query.operations.agentSellingPriceMin,
$lte: query.operations.agentSellingPriceMax,
},
agentShortRentPrice: {
$gte: query.operations.agentShortRentPriceMin,
$lte: query.operations.agentShortRentPriceMax,
},
},
features: {
bathrooms: { $gte: query.features.bathroomsMin },
dorms: { $gte: query.features.dormsMin },
beds: { $gte: query.features.bedsMin },
amenities: { $in: query.features.amenities },
},
}
最后,我减少了这个对象,删除了任何“null”,“false”,“”和“{}”的值。
例如,用户搜索租用中的房屋,在纽约,有2间卧室,带游泳池,最高租金10,000美元。
所以,req.body.query将是
{
name: null,
address: { city: "New York", state: null },
operations: {
rentAvailable: true,
purchaseAvailable: false,
shortRentAvailable: false,
agentRentPriceMin: null,
agentSellingPriceMin: null,
agentShortRentPriceMin: null,
agentRentPriceMax: 10000,
agentSellingPriceMax: null,
agentShortRentPriceMax: null,
},
features: {
bathroomsMin: null,
dormsMin: 2,
bedsMin: null,
amenities: ["pool"],
},
}
接下来,我声明
let queryObj = {
name: null,
address: { city: "New York", state: null },
operations: {
rentAvailable: true,
purchaseAvailable: false,
shortRentAvailable: false,
agentRentPrice: {
$gte: null,
$lte: 10000,
},
agentSellingPrice: {
$gte: null,
$lte: null,
},
agentShortRentPrice: {
$gte: null,
$lte: null,
},
},
features: {
bathrooms: { $gte: null },
dorms: { $gte: 2 },
beds: { $gte: null },
amenities: { $in: ["pool"] },
},
};
我有一个在这里减少这个对象的函数(删除“false”、“null”、“”和“{}”的值):
queryObj = {
address: { city: "New York" },
operations: {
rentAvailable: true,
agentRentPrice: {
$lte: 10000,
},
},
features: {
dorms: { $gte: 2 },
amenities: { $in: ["pool"] },
},
};
如你所见,“query”(因此“queryObj”)会有很大变化;用户可能会使用可用的搜索参数中的任何一个,因此(在我看来)不可能“硬编码”queryObj结构。
我尝试使用
Home.aggregate([{$match:queryObj}])
但没有成功(没有结果)。
我正在尝试的事情是否可能?
英文:
Context:
I am trying to code the back end of an "Advanced Search" option
It is a project I'm coding to practice JS, MongoDB(Mongoose), Next, Node, Etc.
The Schema I'm using is the following:
House Schema:{
name:String,
address:{
street:String
city:String,
state:String
},
operations:{
rent:Boolean,
shortRent:Boolean,
purchase:Boolean,
agentRentPrice:Number,
agentShortRentPrice:Number,
agentSellingPrice:Number},
features:{
bathrooms:Number,
bedrooms:Number,
beds:Number,
amenities:[String],
},
}
Now, the FrontEnd sends the following info (in req.body):
query = {
name: null,
address: { city: null, state: null },
operations: {
rentAvailable: false,
purchaseAvailable: false,
shortRentAvailable: false,
agentRentPriceMin: null,
agentSellingPriceMin: null,
agentShortRentPriceMin: null,
agentRentPriceMax: null,
agentSellingPriceMax: null,
agentShortRentPriceMax: null,
},
features: {
bathroomsMin: null,
dormsMin: null,
bedsMin: null,
amenities: null,
},
}
Of course, those "null" values will be replaced with numbers or strings with the parameters introduced by the user.
With this object, I then declare another:
let queryObj = {
name: query.name,
address: { city: query.address.city, state: query.address.state },
operations: {
rentAvailable: query.operations.rentAvailable,
purchaseAvailable: query.operations.purchaseAvailable,
shortRentAvailable: query.operations.shortRentAvailable,
agentRentPrice: {
$gte: query.operations.agentRentPriceMin,
$lte: query.operations.agentRentPriceMax,
},
agentSellingPrice: {
$gte: query.operations.agentSellingPriceMin,
$lte: query.operations.agentSellingPriceMax,
},
agentShortRentPrice: {
$gte: query.operations.agentShortRentPriceMin,
$lte: query.operations.agentShortRentPriceMax,
},
},
features: {
bathrooms: { $gte: query.features.bathroomsMin },
dorms: { $gte: query.features.dormsMin },
beds: { $gte: query.features.bedsMin },
amenities: { $in: query.features.amenities },
},
}
Finally I reduce this object, removing any "null", "false", "" and "{}" values.
For example, the user searches for: house available for renting, in New York, with 2 bedrooms, with a pool, and max Rent price of $10.000
So, req.body.query will be
{
name: null,
address: { city: "New York", state: null },
operations: {
rentAvailable: true,
purchaseAvailable: false,
shortRentAvailable: false,
agentRentPriceMin: null,
agentSellingPriceMin: null,
agentShortRentPriceMin: null,
agentRentPriceMax: 10000,
agentSellingPriceMax: null,
agentShortRentPriceMax: null,
},
features: {
bathroomsMin: null,
dormsMin: 2,
bedsMin: null,
amenities: ["pool"],
},
}
Next, I declare
let queryObj = {
name: null,
address: { city: "New York", state: null },
operations: {
rentAvailable: true,
purchaseAvailable: false,
shortRentAvailable: false,
agentRentPrice: {
$gte: null,
$lte: 10000,
},
agentSellingPrice: {
$gte: null,
$lte: null,
},
agentShortRentPrice: {
$gte: null,
$lte: null,
},
},
features: {
bathrooms: { $gte: null },
dorms: { $gte: 2 },
beds: { $gte: null },
amenities: { $in: ["pool"] },
},
};
I have a function here that reduces this object (removing "false" "null" "" and "{}" values):
queryObj = {
address: { city: "New York" },
operations: {
rentAvailable: true,
agentRentPrice: {
$lte: 10000,
},
},
features: {
dorms: { $gte: 2 },
amenities: { $in: ["pool"] },
},
};
As you can see, "query" (and therefore "queryObj") will vary a lot; the user may or may not use any of the available search parameters, so (as i see it) it is not possible to "hard-code" the queryObj structure
I've tried using
Home.aggregate([{$match:queryObj}])
without success (returns no results).
Is it possible what I'm trying to do?
答案1
得分: 0
尝试使用函数来构建筛选器:
const body = {
name: null,
address: { city: 'New York', state: null },
operations: {
rentAvailable: true,
purchaseAvailable: false,
shortRentAvailable: false,
agentRentPriceMin: null,
agentSellingPriceMin: null,
agentShortRentPriceMin: null,
agentRentPriceMax: 10000,
agentSellingPriceMax: null,
agentShortRentPriceMax: null,
},
features: {
bathroomsMin: null,
dormsMin: 2,
bedsMin: null,
amenities: ['pool'],
},
};
const buildFilter = (body) => {
const filter = {};
if (body.name != null) {
filter['name'] = body.name;
}
if (body.address.city != null) {
filter['address.city'] = body.address.city;
}
if (body.address.state != null) {
filter['address.state'] = body.address.state;
}
if (body.operations.rentAvailable != null) {
filter['operations.rentAvailable'] = body.operations.rentAvailable;
}
if (body.operations.purchaseAvailable != null) {
filter['operations.purchaseAvailable'] = body.operations.purchaseAvailable;
}
if (body.operations.shortRentAvailable != null) {
filter['operations.shortRentAvailable'] = body.operations.shortRentAvailable;
}
let agentRentPrice = {};
if (body.operations.agentRentPriceMin != null) {
agentRentPrice = { $gte: body.operations.agentRentPriceMin };
}
if (body.operations.agentRentPriceMax != null) {
agentRentPrice = {
...agentRentPrice,
$lte: body.operations.agentRentPriceMax,
};
}
if (Object.keys(agentRentPrice).length > 0) {
filter['operations.agentRentPrice'] = agentRentPrice;
}
let agentSellingPrice = {};
if (body.operations.agentSellingPriceMin != null) {
agentSellingPrice = { $gte: body.operations.agentSellingPriceMin };
}
if (body.operations.agentSellingPriceMax != null) {
agentSellingPrice = {
...agentSellingPrice,
$lte: body.operations.agentSellingPriceMax,
};
}
if (Object.keys(agentSellingPrice).length > 0) {
filter['operations.agentSellingPrice'] = agentSellingPrice;
}
let agentShortRentPrice = {};
if (body.operations.agentShortRentPriceMin != null) {
agentShortRentPrice = { $gte: body.operations.agentShortRentPriceMin };
}
if (body.operations.agentShortRentPriceMax != null) {
agentShortRentPrice = {
...agentShortRentPrice,
$lte: body.operations.agentShortRentPriceMax,
};
}
if (Object.keys(agentShortRentPrice).length > 0) {
filter['operations.agentShortRentPrice'] = agentShortRentPrice;
}
if (body.features.bathroomsMin != null) {
filter['features.bathrooms'] = { $gte: body.features.bathroomsMin };
}
if (body.features.dormsMin != null) {
filter['features.dorms'] = { $gte: body.features.dormsMin };
}
if (body.features.bedsMin != null) {
filter['features.beds'] = { $gte: body.features.bedsMin };
}
if (body.features.amenities != null) {
filter['features.amenities'] = { $in: body.features.amenities };
}
return filter;
};
console.log(buildFilter(body));
略显冗长,但这是因为您的body
属性与筛选器属性之间没有一对一的对应关系。
英文:
Try to use a function to build the filter:
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
const body = {
name: null,
address: { city: 'New York', state: null },
operations: {
rentAvailable: true,
purchaseAvailable: false,
shortRentAvailable: false,
agentRentPriceMin: null,
agentSellingPriceMin: null,
agentShortRentPriceMin: null,
agentRentPriceMax: 10000,
agentSellingPriceMax: null,
agentShortRentPriceMax: null,
},
features: {
bathroomsMin: null,
dormsMin: 2,
bedsMin: null,
amenities: ['pool'],
},
};
const buildFilter = (body) => {
const filter = {};
if (body.name != null) {
filter['name'] = body.name;
}
if (body.address.city != null) {
filter['address.city'] = body.address.city;
}
if (body.address.state != null) {
filter['address.state'] = body.address.state;
}
if (body.operations.rentAvailable != null) {
filter['operations.rentAvailable'] = body.operations.rentAvailable;
}
if (body.operations.purchaseAvailable != null) {
filter['operations.purchaseAvailable'] = body.operations.purchaseAvailable;
}
if (body.operations.shortRentAvailable != null) {
filter['operations.shortRentAvailable'] =
body.operations.shortRentAvailable;
}
let agentRentPrice = {};
if (body.operations.agentRentPriceMin != null) {
agentRentPrice = { $gte: body.operations.agentRentPriceMin };
}
if (body.operations.agentRentPriceMax != null) {
agentRentPrice = {
...agentRentPrice,
$lte: body.operations.agentRentPriceMax,
};
}
if (Object.keys(agentRentPrice).length > 0) {
filter['operations.agentRentPrice'] = agentRentPrice;
}
let agentSellingPrice = {};
if (body.operations.agentSellingPriceMin != null) {
agentSellingPrice = { $gte: body.operations.agentSellingPriceMin };
}
if (body.operations.agentSellingPriceMax != null) {
agentSellingPrice = {
...agentSellingPrice,
$lte: body.operations.agentSellingPriceMax,
};
}
if (Object.keys(agentSellingPrice).length > 0) {
filter['operations.agentSellingPrice'] = agentSellingPrice;
}
let agentShortRentPrice = {};
if (body.operations.agentShortRentPriceMin != null) {
agentShortRentPrice = { $gte: body.operations.agentShortRentPriceMin };
}
if (body.operations.agentShortRentPriceMax != null) {
agentShortRentPrice = {
...agentShortRentPrice,
$lte: body.operations.agentShortRentPriceMax,
};
}
if (Object.keys(agentShortRentPrice).length > 0) {
filter['operations.agentShortRentPrice'] = agentShortRentPrice;
}
if (body.features.bathrooms != null) {
filter['features.bathrooms'] = { $gte: body.features.bathrooms };
}
if (body.features.dorms != null) {
filter['features.dorms'] = { $gte: body.features.dorms };
}
if (body.features.beds != null) {
filter['features.beds'] = { $gte: body.features.beds };
}
if (body.features.amenities != null) {
filter['features.amenities'] = { $in: body.features.amenities };
}
return filter;
};
console.log(buildFilter(body));
<!-- end snippet -->
A little verbose, but it is due to the fact that you don't have a 1-on-1 correspondence between the attributes of the body and your filter's properties.
答案2
得分: 0
你可以通过在后端动态创建筛选器来解决这个问题。基本上,你会从一个空的筛选器开始,然后检查每个用户输入,并将其添加到筛选器中(如果存在)。这样,你就不必担心用户是否会发送多个筛选器,或者是否根本不会发送筛选器。一切都将动态添加。
const queryObj = {
address: { city: "New York" },
operations: {
rentAvailable: true,
agentRentPrice: {
$lte: 10000,
},
},
features: {
dorms: { $gte: 2 },
amenities: { $in: ["pool"] },
},
};
// 初始化一个空的筛选器。
const filter = {};
if (queryObj?.address?.city) filter['address.city'] = queryObj.address.city;
if (typeof queryObj?.operations?.rentAvailable === boolean) filter['operations.rentAvailable'] = queryObj.operations.rentAvailable;
if (queryObj?.operations?.agentRentPrice?.$lte) filter['operations.agentRentPrice'] = { $lte: queryObj.operations.agentRentPrice.$lte };
英文:
You can solve this by creating the filter dynamically on the backend. Basically, you will start with an empty filter, and then you will check each user input, and add it to the filter if exists. That way, you don't have to worry if the user will send multiple filters, or if it will not send filters at all. Everything will be added dynamically.
const queryObj = {
address: { city: "New York" },
operations: {
rentAvailable: true,
agentRentPrice: {
$lte: 10000,
},
},
features: {
dorms: { $gte: 2 },
amenities: { $in: ["pool"] },
},
};
// Initialize empty filter.
const filter = {};
if (queryObj?.address?.city) filter['address.city'] = queryObj.address.city;
if (typeof queryObj?.operations?.rentAvailable === boolean) filter['operations.rentAvailable'] = queryObj.operations.rentAvailable;
if (queryObj?.operations?.agentRentPrice?.$lte) filter['operations.agentRentPrice'] = { $lte: queryObj.operations.agentRentPrice.$lte };
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论